summaryrefslogtreecommitdiffstats
path: root/compiler
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-18 02:49:50 +0000
commit9835e2ae736235810b4ea1c162ca5e65c547e770 (patch)
tree3fcebf40ed70e581d776a8a4c65923e8ec20e026 /compiler
parentReleasing progress-linux version 1.70.0+dfsg2-1~progress7.99u1. (diff)
downloadrustc-9835e2ae736235810b4ea1c162ca5e65c547e770.tar.xz
rustc-9835e2ae736235810b4ea1c162ca5e65c547e770.zip
Merging upstream version 1.71.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'compiler')
-rw-r--r--compiler/rustc_abi/src/layout.rs668
-rw-r--r--compiler/rustc_abi/src/lib.rs64
-rw-r--r--compiler/rustc_arena/src/lib.rs48
-rw-r--r--compiler/rustc_ast/src/ast.rs71
-rw-r--r--compiler/rustc_ast/src/attr/mod.rs42
-rw-r--r--compiler/rustc_ast/src/expand/allocator.rs22
-rw-r--r--compiler/rustc_ast/src/lib.rs1
-rw-r--r--compiler/rustc_ast/src/mut_visit.rs13
-rw-r--r--compiler/rustc_ast/src/node_id.rs8
-rw-r--r--compiler/rustc_ast/src/ptr.rs3
-rw-r--r--compiler/rustc_ast/src/token.rs9
-rw-r--r--compiler/rustc_ast/src/tokenstream.rs17
-rw-r--r--compiler/rustc_ast/src/util/literal.rs66
-rw-r--r--compiler/rustc_ast/src/util/parser.rs29
-rw-r--r--compiler/rustc_ast/src/visit.rs13
-rw-r--r--compiler/rustc_ast_lowering/Cargo.toml1
-rw-r--r--compiler/rustc_ast_lowering/messages.ftl168
-rw-r--r--compiler/rustc_ast_lowering/src/errors.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/expr.rs93
-rw-r--r--compiler/rustc_ast_lowering/src/format.rs59
-rw-r--r--compiler/rustc_ast_lowering/src/index.rs2
-rw-r--r--compiler/rustc_ast_lowering/src/item.rs36
-rw-r--r--compiler/rustc_ast_lowering/src/lib.rs108
-rw-r--r--compiler/rustc_ast_lowering/src/path.rs2
-rw-r--r--compiler/rustc_ast_passes/Cargo.toml1
-rw-r--r--compiler/rustc_ast_passes/messages.ftl294
-rw-r--r--compiler/rustc_ast_passes/src/ast_validation.rs24
-rw-r--r--compiler/rustc_ast_passes/src/errors.rs17
-rw-r--r--compiler/rustc_ast_passes/src/feature_gate.rs15
-rw-r--r--compiler/rustc_ast_passes/src/lib.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pp.rs2
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs11
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs33
-rw-r--r--compiler/rustc_attr/Cargo.toml1
-rw-r--r--compiler/rustc_attr/messages.ftl128
-rw-r--r--compiler/rustc_attr/src/builtin.rs44
-rw-r--r--compiler/rustc_attr/src/lib.rs2
-rw-r--r--compiler/rustc_baked_icu_data/Cargo.toml10
-rw-r--r--compiler/rustc_baked_icu_data/src/data/fallback/likelysubtags_v1/und.rs.data702
-rw-r--r--compiler/rustc_baked_icu_data/src/data/fallback/parents_v1/und.rs.data207
-rw-r--r--compiler/rustc_baked_icu_data/src/data/fallback/supplement/co_v1/und.rs.data26
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/en.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/es.rs.data780
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/fr.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/it.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/ja.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/pt.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/ru.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/tr.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/und.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/zh-Hant.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/list/and_v1/zh.rs.data48
-rw-r--r--compiler/rustc_baked_icu_data/src/data/mod.rs11
-rw-r--r--compiler/rustc_borrowck/Cargo.toml2
-rw-r--r--compiler/rustc_borrowck/messages.ftl291
-rw-r--r--compiler/rustc_borrowck/src/borrow_set.rs4
-rw-r--r--compiler/rustc_borrowck/src/borrowck_errors.rs1
-rw-r--r--compiler/rustc_borrowck/src/constraints/graph.rs2
-rw-r--r--compiler/rustc_borrowck/src/constraints/mod.rs2
-rw-r--r--compiler/rustc_borrowck/src/consumers.rs99
-rw-r--r--compiler/rustc_borrowck/src/dataflow.rs132
-rw-r--r--compiler/rustc_borrowck/src/def_use.rs8
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs437
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs17
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mod.rs298
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/move_errors.rs55
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs555
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs13
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_errors.rs22
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/region_name.rs2
-rw-r--r--compiler/rustc_borrowck/src/diagnostics/var_name.rs4
-rw-r--r--compiler/rustc_borrowck/src/facts.rs5
-rw-r--r--compiler/rustc_borrowck/src/invalidation.rs12
-rw-r--r--compiler/rustc_borrowck/src/lib.rs140
-rw-r--r--compiler/rustc_borrowck/src/location.rs8
-rw-r--r--compiler/rustc_borrowck/src/member_constraints.rs4
-rw-r--r--compiler/rustc_borrowck/src/nll.rs35
-rw-r--r--compiler/rustc_borrowck/src/place_ext.rs2
-rw-r--r--compiler/rustc_borrowck/src/places_conflict.rs4
-rw-r--r--compiler/rustc_borrowck/src/region_infer/mod.rs31
-rw-r--r--compiler/rustc_borrowck/src/region_infer/opaque_types.rs11
-rw-r--r--compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs13
-rw-r--r--compiler/rustc_borrowck/src/region_infer/values.rs22
-rw-r--r--compiler/rustc_borrowck/src/renumber.rs10
-rw-r--r--compiler/rustc_borrowck/src/session_diagnostics.rs215
-rw-r--r--compiler/rustc_borrowck/src/type_check/canonical.rs68
-rw-r--r--compiler/rustc_borrowck/src/type_check/free_region_relations.rs21
-rw-r--r--compiler/rustc_borrowck/src/type_check/input_output.rs5
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs2
-rw-r--r--compiler/rustc_borrowck/src/type_check/liveness/trace.rs18
-rw-r--r--compiler/rustc_borrowck/src/type_check/mod.rs223
-rw-r--r--compiler/rustc_borrowck/src/type_check/relate_tys.rs42
-rw-r--r--compiler/rustc_borrowck/src/universal_regions.rs66
-rw-r--r--compiler/rustc_borrowck/src/util/collect_writes.rs (renamed from compiler/rustc_const_eval/src/util/collect_writes.rs)0
-rw-r--r--compiler/rustc_borrowck/src/util/mod.rs3
-rw-r--r--compiler/rustc_builtin_macros/Cargo.toml2
-rw-r--r--compiler/rustc_builtin_macros/messages.ftl203
-rw-r--r--compiler/rustc_builtin_macros/src/asm.rs156
-rw-r--r--compiler/rustc_builtin_macros/src/assert.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/assert/context.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/cfg_eval.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/concat.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/concat_bytes.rs5
-rw-r--r--compiler/rustc_builtin_macros/src/concat_idents.rs2
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/bounds.rs23
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/clone.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/deriving/generic/mod.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/edition_panic.rs1
-rw-r--r--compiler/rustc_builtin_macros/src/env.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/errors.rs191
-rw-r--r--compiler/rustc_builtin_macros/src/format.rs18
-rw-r--r--compiler/rustc_builtin_macros/src/format_foreign.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/global_allocator.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/lib.rs4
-rw-r--r--compiler/rustc_builtin_macros/src/proc_macro_harness.rs6
-rw-r--r--compiler/rustc_builtin_macros/src/source_util.rs8
-rw-r--r--compiler/rustc_builtin_macros/src/test.rs16
-rw-r--r--compiler/rustc_builtin_macros/src/test_harness.rs12
-rw-r--r--compiler/rustc_builtin_macros/src/trace_macros.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md18
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml13
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js162
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json571
-rw-r--r--compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json11
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml7
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/main.yml62
-rw-r--r--compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml18
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.lock143
-rw-r--r--compiler/rustc_codegen_cranelift/Cargo.toml16
-rw-r--r--compiler/rustc_codegen_cranelift/Readme.md5
-rw-r--r--compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock28
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/mod.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/build_system/tests.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/example/alloc_example.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/example/dst-field-align.rs41
-rw-r--r--compiler/rustc_codegen_cranelift/example/example.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-72793.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs5
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core.rs52
-rw-r--r--compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs3
-rw-r--r--compiler/rustc_codegen_cranelift/example/mod_bench.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/example/std_example.rs27
-rw-r--r--compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs11
-rw-r--r--compiler/rustc_codegen_cranelift/rust-toolchain2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs8
-rw-r--r--compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs8
-rwxr-xr-xcompiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh72
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/comments.rs32
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/mod.rs24
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/abi/returning.rs6
-rw-r--r--compiler/rustc_codegen_cranelift/src/allocator.rs79
-rw-r--r--compiler/rustc_codegen_cranelift/src/analyze.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/base.rs85
-rw-r--r--compiler/rustc_codegen_cranelift/src/cast.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/codegen_i128.rs147
-rw-r--r--compiler/rustc_codegen_cranelift/src/common.rs28
-rw-r--r--compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs67
-rw-r--r--compiler/rustc_codegen_cranelift/src/constant.rs12
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/aot.rs10
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/jit.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/driver/mod.rs29
-rw-r--r--compiler/rustc_codegen_cranelift/src/global_asm.rs1
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs2
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs7
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs18
-rw-r--r--compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs16
-rw-r--r--compiler/rustc_codegen_cranelift/src/lib.rs14
-rw-r--r--compiler/rustc_codegen_cranelift/src/main_shim.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/num.rs4
-rw-r--r--compiler/rustc_codegen_cranelift/src/pretty_clif.rs59
-rw-r--r--compiler/rustc_codegen_cranelift/src/value_and_place.rs332
-rwxr-xr-xcompiler/rustc_codegen_cranelift/y.rs6
-rw-r--r--compiler/rustc_codegen_gcc/messages.ftl66
-rw-r--r--compiler/rustc_codegen_gcc/src/allocator.rs125
-rw-r--r--compiler/rustc_codegen_gcc/src/asm.rs7
-rw-r--r--compiler/rustc_codegen_gcc/src/builder.rs15
-rw-r--r--compiler/rustc_codegen_gcc/src/callee.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/intrinsic/mod.rs14
-rw-r--r--compiler/rustc_codegen_gcc/src/lib.rs5
-rw-r--r--compiler/rustc_codegen_gcc/src/mono_item.rs2
-rw-r--r--compiler/rustc_codegen_gcc/src/type_.rs12
-rw-r--r--compiler/rustc_codegen_llvm/Cargo.toml4
-rw-r--r--compiler/rustc_codegen_llvm/messages.ftl108
-rw-r--r--compiler/rustc_codegen_llvm/src/allocator.rs145
-rw-r--r--compiler/rustc_codegen_llvm/src/asm.rs25
-rw-r--r--compiler/rustc_codegen_llvm/src/back/archive.rs12
-rw-r--r--compiler/rustc_codegen_llvm/src/back/lto.rs49
-rw-r--r--compiler/rustc_codegen_llvm/src/back/write.rs10
-rw-r--r--compiler/rustc_codegen_llvm/src/builder.rs127
-rw-r--r--compiler/rustc_codegen_llvm/src/callee.rs6
-rw-r--r--compiler/rustc_codegen_llvm/src/common.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/context.rs19
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs14
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs2
-rw-r--r--compiler/rustc_codegen_llvm/src/debuginfo/mod.rs22
-rw-r--r--compiler/rustc_codegen_llvm/src/declare.rs63
-rw-r--r--compiler/rustc_codegen_llvm/src/errors.rs4
-rw-r--r--compiler/rustc_codegen_llvm/src/intrinsic.rs30
-rw-r--r--compiler/rustc_codegen_llvm/src/lib.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/ffi.rs17
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm/mod.rs1
-rw-r--r--compiler/rustc_codegen_llvm/src/llvm_util.rs181
-rw-r--r--compiler/rustc_codegen_llvm/src/mono_item.rs7
-rw-r--r--compiler/rustc_codegen_llvm/src/type_.rs37
-rw-r--r--compiler/rustc_codegen_ssa/Cargo.toml15
-rw-r--r--compiler/rustc_codegen_ssa/messages.ftl313
-rw-r--r--compiler/rustc_codegen_ssa/src/back/archive.rs1
-rw-r--r--compiler/rustc_codegen_ssa/src/back/link.rs169
-rw-r--r--compiler/rustc_codegen_ssa/src/back/linker.rs26
-rw-r--r--compiler/rustc_codegen_ssa/src/back/metadata.rs91
-rw-r--r--compiler/rustc_codegen_ssa/src/back/symbol_export.rs17
-rw-r--r--compiler/rustc_codegen_ssa/src/back/write.rs16
-rw-r--r--compiler/rustc_codegen_ssa/src/base.rs41
-rw-r--r--compiler/rustc_codegen_ssa/src/codegen_attrs.rs33
-rw-r--r--compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/coverageinfo/map.rs2
-rw-r--r--compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/errors.rs36
-rw-r--r--compiler/rustc_codegen_ssa/src/lib.rs32
-rw-r--r--compiler/rustc_codegen_ssa/src/meth.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/analyze.rs8
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/block.rs71
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/debuginfo.rs153
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/intrinsic.rs7
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/mod.rs18
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/operand.rs63
-rw-r--r--compiler/rustc_codegen_ssa/src/mir/rvalue.rs95
-rw-r--r--compiler/rustc_codegen_ssa/src/target_features.rs23
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/backend.rs13
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/builder.rs4
-rw-r--r--compiler/rustc_codegen_ssa/src/traits/type_.rs12
-rw-r--r--compiler/rustc_const_eval/Cargo.toml1
-rw-r--r--compiler/rustc_const_eval/messages.ftl92
-rw-r--r--compiler/rustc_const_eval/src/const_eval/error.rs13
-rw-r--r--compiler/rustc_const_eval/src/const_eval/eval_queries.rs8
-rw-r--r--compiler/rustc_const_eval/src/const_eval/fn_queries.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/machine.rs14
-rw-r--r--compiler/rustc_const_eval/src/const_eval/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/const_eval/valtrees.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/discriminant.rs17
-rw-r--r--compiler/rustc_const_eval/src/interpret/eval_context.rs51
-rw-r--r--compiler/rustc_const_eval/src/interpret/intern.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics.rs10
-rw-r--r--compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs6
-rw-r--r--compiler/rustc_const_eval/src/interpret/machine.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/memory.rs27
-rw-r--r--compiler/rustc_const_eval/src/interpret/operand.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/operator.rs26
-rw-r--r--compiler/rustc_const_eval/src/interpret/place.rs2
-rw-r--r--compiler/rustc_const_eval/src/interpret/step.rs19
-rw-r--r--compiler/rustc_const_eval/src/interpret/terminator.rs5
-rw-r--r--compiler/rustc_const_eval/src/interpret/util.rs8
-rw-r--r--compiler/rustc_const_eval/src/interpret/validity.rs22
-rw-r--r--compiler/rustc_const_eval/src/lib.rs4
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/check.rs8
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/mod.rs2
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/ops.rs30
-rw-r--r--compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/promote_consts.rs7
-rw-r--r--compiler/rustc_const_eval/src/transform/validate.rs82
-rw-r--r--compiler/rustc_const_eval/src/util/compare_types.rs4
-rw-r--r--compiler/rustc_const_eval/src/util/mod.rs5
-rw-r--r--compiler/rustc_const_eval/src/util/type_name.rs3
-rw-r--r--compiler/rustc_data_structures/Cargo.toml5
-rw-r--r--compiler/rustc_data_structures/src/aligned.rs33
-rw-r--r--compiler/rustc_data_structures/src/fingerprint.rs48
-rw-r--r--compiler/rustc_data_structures/src/fingerprint/tests.rs7
-rw-r--r--compiler/rustc_data_structures/src/functor.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/mod.rs132
-rw-r--r--compiler/rustc_data_structures/src/graph/dominators/tests.rs41
-rw-r--r--compiler/rustc_data_structures/src/graph/iterate/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/scc/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/graph/vec_graph/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/hashes.rs132
-rw-r--r--compiler/rustc_data_structures/src/lib.rs30
-rw-r--r--compiler/rustc_data_structures/src/marker.rs257
-rw-r--r--compiler/rustc_data_structures/src/memmap.rs3
-rw-r--r--compiler/rustc_data_structures/src/obligation_forest/mod.rs2
-rw-r--r--compiler/rustc_data_structures/src/owned_slice.rs45
-rw-r--r--compiler/rustc_data_structures/src/owned_slice/tests.rs20
-rw-r--r--compiler/rustc_data_structures/src/profiling.rs51
-rw-r--r--compiler/rustc_data_structures/src/profiling/tests.rs19
-rw-r--r--compiler/rustc_data_structures/src/sharded.rs6
-rw-r--r--compiler/rustc_data_structures/src/sip128.rs196
-rw-r--r--compiler/rustc_data_structures/src/sorted_map/index_map.rs2
-rw-r--r--compiler/rustc_data_structures/src/sso/map.rs7
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher.rs40
-rw-r--r--compiler/rustc_data_structures/src/stable_hasher/tests.rs2
-rw-r--r--compiler/rustc_data_structures/src/svh.rs40
-rw-r--r--compiler/rustc_data_structures/src/sync.rs274
-rw-r--r--compiler/rustc_data_structures/src/sync/vec.rs2
-rw-r--r--compiler/rustc_data_structures/src/sync/worker_local.rs173
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr.rs289
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy.rs321
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs50
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop.rs124
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs71
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs144
-rw-r--r--compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs34
-rw-r--r--compiler/rustc_data_structures/src/vec_linked_list.rs2
-rw-r--r--compiler/rustc_data_structures/src/work_queue.rs2
-rw-r--r--compiler/rustc_driver_impl/Cargo.toml11
-rw-r--r--compiler/rustc_driver_impl/messages.ftl20
-rw-r--r--compiler/rustc_driver_impl/src/args.rs5
-rw-r--r--compiler/rustc_driver_impl/src/lib.rs246
-rw-r--r--compiler/rustc_driver_impl/src/pretty.rs14
-rw-r--r--compiler/rustc_driver_impl/src/print.rs20
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0026.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0208.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0311.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0457.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0576.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0609.md2
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0726.md4
-rw-r--r--compiler/rustc_error_codes/src/error_codes/E0771.md4
-rw-r--r--compiler/rustc_error_messages/Cargo.toml7
-rw-r--r--compiler/rustc_error_messages/src/lib.rs52
-rw-r--r--compiler/rustc_errors/Cargo.toml4
-rw-r--r--compiler/rustc_errors/messages.ftl22
-rw-r--r--compiler/rustc_errors/src/diagnostic_builder.rs11
-rw-r--r--compiler/rustc_errors/src/emitter.rs59
-rw-r--r--compiler/rustc_errors/src/lib.rs80
-rw-r--r--compiler/rustc_errors/src/lock.rs3
-rw-r--r--compiler/rustc_errors/src/tests.rs10
-rw-r--r--compiler/rustc_expand/Cargo.toml1
-rw-r--r--compiler/rustc_expand/messages.ftl176
-rw-r--r--compiler/rustc_expand/src/base.rs31
-rw-r--r--compiler/rustc_expand/src/errors.rs10
-rw-r--r--compiler/rustc_expand/src/expand.rs19
-rw-r--r--compiler/rustc_expand/src/lib.rs2
-rw-r--r--compiler/rustc_expand/src/mbe/diagnostics.rs4
-rw-r--r--compiler/rustc_expand/src/mbe/macro_check.rs19
-rw-r--r--compiler/rustc_expand/src/mbe/macro_parser.rs23
-rw-r--r--compiler/rustc_expand/src/mbe/macro_rules.rs19
-rw-r--r--compiler/rustc_expand/src/mbe/metavar_expr.rs6
-rw-r--r--compiler/rustc_expand/src/mbe/quoted.rs8
-rw-r--r--compiler/rustc_expand/src/mbe/transcribe.rs2
-rw-r--r--compiler/rustc_expand/src/placeholders.rs1
-rw-r--r--compiler/rustc_expand/src/proc_macro.rs4
-rw-r--r--compiler/rustc_expand/src/proc_macro_server.rs17
-rw-r--r--compiler/rustc_expand/src/tests.rs4
-rw-r--r--compiler/rustc_feature/src/accepted.rs4
-rw-r--r--compiler/rustc_feature/src/active.rs20
-rw-r--r--compiler/rustc_feature/src/builtin_attrs.rs23
-rw-r--r--compiler/rustc_feature/src/lib.rs11
-rw-r--r--compiler/rustc_feature/src/removed.rs2
-rw-r--r--compiler/rustc_fluent_macro/Cargo.toml16
-rw-r--r--compiler/rustc_fluent_macro/src/fluent.rs (renamed from compiler/rustc_macros/src/diagnostics/fluent.rs)2
-rw-r--r--compiler/rustc_fluent_macro/src/lib.rs64
-rw-r--r--compiler/rustc_graphviz/src/lib.rs10
-rw-r--r--compiler/rustc_hir/src/arena.rs45
-rw-r--r--compiler/rustc_hir/src/def.rs5
-rw-r--r--compiler/rustc_hir/src/definitions.rs8
-rw-r--r--compiler/rustc_hir/src/errors.rs10
-rw-r--r--compiler/rustc_hir/src/hir.rs264
-rw-r--r--compiler/rustc_hir/src/hir_id.rs7
-rw-r--r--compiler/rustc_hir/src/intravisit.rs4
-rw-r--r--compiler/rustc_hir/src/lang_items.rs12
-rw-r--r--compiler/rustc_hir/src/lib.rs1
-rw-r--r--compiler/rustc_hir/src/tests.rs9
-rw-r--r--compiler/rustc_hir_analysis/Cargo.toml4
-rw-r--r--compiler/rustc_hir_analysis/messages.ftl332
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/errors.rs16
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/generics.rs8
-rw-r--r--compiler/rustc_hir_analysis/src/astconv/mod.rs328
-rw-r--r--compiler/rustc_hir_analysis/src/autoderef.rs78
-rw-r--r--compiler/rustc_hir_analysis/src/bounds.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/check.rs72
-rw-r--r--compiler/rustc_hir_analysis/src/check/compare_impl_item.rs60
-rw-r--r--compiler/rustc_hir_analysis/src/check/dropck.rs351
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsic.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/check/intrinsicck.rs68
-rw-r--r--compiler/rustc_hir_analysis/src/check/mod.rs201
-rw-r--r--compiler/rustc_hir_analysis/src/check/region.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/check/wfcheck.rs61
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/builtin.rs287
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/mod.rs13
-rw-r--r--compiler/rustc_hir_analysis/src/coherence/orphan.rs29
-rw-r--r--compiler/rustc_hir_analysis/src/collect.rs58
-rw-r--r--compiler/rustc_hir_analysis/src/collect/generics_of.rs36
-rw-r--r--compiler/rustc_hir_analysis/src/collect/item_bounds.rs28
-rw-r--r--compiler/rustc_hir_analysis/src/collect/predicates_of.rs131
-rw-r--r--compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs86
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of.rs583
-rw-r--r--compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs298
-rw-r--r--compiler/rustc_hir_analysis/src/constrained_generic_params.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/errors.rs230
-rw-r--r--compiler/rustc_hir_analysis/src/hir_wf_check.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs54
-rw-r--r--compiler/rustc_hir_analysis/src/lib.rs10
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs3
-rw-r--r--compiler/rustc_hir_analysis/src/outlives/mod.rs4
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs22
-rw-r--r--compiler/rustc_hir_analysis/src/variance/constraints.rs2
-rw-r--r--compiler/rustc_hir_analysis/src/variance/mod.rs7
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs29
-rw-r--r--compiler/rustc_hir_typeck/Cargo.toml1
-rw-r--r--compiler/rustc_hir_typeck/messages.ftl115
-rw-r--r--compiler/rustc_hir_typeck/src/_match.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/callee.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/cast.rs14
-rw-r--r--compiler/rustc_hir_typeck/src/check.rs23
-rw-r--r--compiler/rustc_hir_typeck/src/closure.rs8
-rw-r--r--compiler/rustc_hir_typeck/src/coercion.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/demand.rs267
-rw-r--r--compiler/rustc_hir_typeck/src/errors.rs105
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs249
-rw-r--r--compiler/rustc_hir_typeck/src/expr_use_visitor.rs20
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs105
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs43
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs86
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs29
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs74
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs2
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs7
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/generator_interior/mod.rs10
-rw-r--r--compiler/rustc_hir_typeck/src/inherited.rs5
-rw-r--r--compiler/rustc_hir_typeck/src/intrinsicck.rs16
-rw-r--r--compiler/rustc_hir_typeck/src/lib.rs56
-rw-r--r--compiler/rustc_hir_typeck/src/mem_categorization.rs3
-rw-r--r--compiler/rustc_hir_typeck/src/method/confirm.rs27
-rw-r--r--compiler/rustc_hir_typeck/src/method/mod.rs12
-rw-r--r--compiler/rustc_hir_typeck/src/method/prelude2021.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/method/probe.rs17
-rw-r--r--compiler/rustc_hir_typeck/src/method/suggest.rs296
-rw-r--r--compiler/rustc_hir_typeck/src/op.rs62
-rw-r--r--compiler/rustc_hir_typeck/src/pat.rs36
-rw-r--r--compiler/rustc_hir_typeck/src/place_op.rs50
-rw-r--r--compiler/rustc_hir_typeck/src/upvar.rs48
-rw-r--r--compiler/rustc_hir_typeck/src/writeback.rs113
-rw-r--r--compiler/rustc_incremental/Cargo.toml1
-rw-r--r--compiler/rustc_incremental/messages.ftl140
-rw-r--r--compiler/rustc_incremental/src/lib.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/dirty_clean.rs2
-rw-r--r--compiler/rustc_incremental/src/persist/file_format.rs35
-rw-r--r--compiler/rustc_incremental/src/persist/fs.rs4
-rw-r--r--compiler/rustc_incremental/src/persist/load.rs42
-rw-r--r--compiler/rustc_incremental/src/persist/save.rs4
-rw-r--r--compiler/rustc_index/src/bit_set.rs12
-rw-r--r--compiler/rustc_index/src/idx.rs45
-rw-r--r--compiler/rustc_index/src/interval.rs36
-rw-r--r--compiler/rustc_index/src/lib.rs7
-rw-r--r--compiler/rustc_index/src/slice.rs256
-rw-r--r--compiler/rustc_index/src/vec.rs424
-rw-r--r--compiler/rustc_infer/Cargo.toml1
-rw-r--r--compiler/rustc_infer/messages.ftl591
-rw-r--r--compiler/rustc_infer/src/errors/mod.rs14
-rw-r--r--compiler/rustc_infer/src/infer/at.rs3
-rw-r--r--compiler/rustc_infer/src/infer/canonical/canonicalizer.rs12
-rw-r--r--compiler/rustc_infer/src/infer/canonical/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/canonical/query_response.rs40
-rw-r--r--compiler/rustc_infer/src/infer/combine.rs620
-rw-r--r--compiler/rustc_infer/src/infer/equate.rs11
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/mod.rs36
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs12
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs2
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs15
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs21
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs4
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs32
-rw-r--r--compiler/rustc_infer/src/infer/error_reporting/suggest.rs83
-rw-r--r--compiler/rustc_infer/src/infer/freshen.rs2
-rw-r--r--compiler/rustc_infer/src/infer/generalize.rs479
-rw-r--r--compiler/rustc_infer/src/infer/higher_ranked/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/lattice.rs5
-rw-r--r--compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs26
-rw-r--r--compiler/rustc_infer/src/infer/mod.rs72
-rw-r--r--compiler/rustc_infer/src/infer/nll_relate/mod.rs363
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types.rs108
-rw-r--r--compiler/rustc_infer/src/infer/opaque_types/table.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/components.rs40
-rw-r--r--compiler/rustc_infer/src/infer/outlives/mod.rs2
-rw-r--r--compiler/rustc_infer/src/infer/outlives/obligations.rs31
-rw-r--r--compiler/rustc_infer/src/infer/outlives/test_type_match.rs12
-rw-r--r--compiler/rustc_infer/src/infer/outlives/verify.rs13
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/leak_check.rs2
-rw-r--r--compiler/rustc_infer/src/infer/region_constraints/mod.rs6
-rw-r--r--compiler/rustc_infer/src/infer/resolve.rs4
-rw-r--r--compiler/rustc_infer/src/infer/sub.rs11
-rw-r--r--compiler/rustc_infer/src/lib.rs2
-rw-r--r--compiler/rustc_infer/src/traits/engine.rs2
-rw-r--r--compiler/rustc_infer/src/traits/error_reporting/mod.rs2
-rw-r--r--compiler/rustc_infer/src/traits/mod.rs10
-rw-r--r--compiler/rustc_infer/src/traits/project.rs4
-rw-r--r--compiler/rustc_infer/src/traits/util.rs12
-rw-r--r--compiler/rustc_interface/Cargo.toml3
-rw-r--r--compiler/rustc_interface/messages.ftl54
-rw-r--r--compiler/rustc_interface/src/interface.rs111
-rw-r--r--compiler/rustc_interface/src/lib.rs2
-rw-r--r--compiler/rustc_interface/src/passes.rs54
-rw-r--r--compiler/rustc_interface/src/proc_macro_decls.rs2
-rw-r--r--compiler/rustc_interface/src/queries.rs7
-rw-r--r--compiler/rustc_interface/src/tests.rs13
-rw-r--r--compiler/rustc_interface/src/util.rs26
-rw-r--r--compiler/rustc_lexer/src/lib.rs111
-rw-r--r--compiler/rustc_lexer/src/unescape.rs278
-rw-r--r--compiler/rustc_lint/Cargo.toml1
-rw-r--r--compiler/rustc_lint/messages.ftl713
-rw-r--r--compiler/rustc_lint/src/builtin.rs105
-rw-r--r--compiler/rustc_lint/src/context.rs104
-rw-r--r--compiler/rustc_lint/src/drop_forget_useless.rs164
-rw-r--r--compiler/rustc_lint/src/early.rs2
-rw-r--r--compiler/rustc_lint/src/enum_intrinsics_non_enums.rs2
-rw-r--r--compiler/rustc_lint/src/errors.rs2
-rw-r--r--compiler/rustc_lint/src/expect.rs2
-rw-r--r--compiler/rustc_lint/src/internal.rs87
-rw-r--r--compiler/rustc_lint/src/late.rs10
-rw-r--r--compiler/rustc_lint/src/levels.rs14
-rw-r--r--compiler/rustc_lint/src/lib.rs8
-rw-r--r--compiler/rustc_lint/src/lints.rs53
-rw-r--r--compiler/rustc_lint/src/non_fmt_panic.rs2
-rw-r--r--compiler/rustc_lint/src/nonstandard_style.rs8
-rw-r--r--compiler/rustc_lint/src/noop_method_call.rs117
-rw-r--r--compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs4
-rw-r--r--compiler/rustc_lint/src/types.rs6
-rw-r--r--compiler/rustc_lint/src/unused.rs95
-rw-r--r--compiler/rustc_lint_defs/src/builtin.rs192
-rw-r--r--compiler/rustc_lint_defs/src/lib.rs3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp3
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp109
-rw-r--r--compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp134
-rw-r--r--compiler/rustc_macros/Cargo.toml4
-rw-r--r--compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs9
-rw-r--r--compiler/rustc_macros/src/diagnostics/mod.rs4
-rw-r--r--compiler/rustc_macros/src/diagnostics/subdiagnostic.rs33
-rw-r--r--compiler/rustc_macros/src/diagnostics/utils.rs9
-rw-r--r--compiler/rustc_macros/src/lib.rs54
-rw-r--r--compiler/rustc_macros/src/newtype.rs2
-rw-r--r--compiler/rustc_macros/src/query.rs14
-rw-r--r--compiler/rustc_metadata/Cargo.toml2
-rw-r--r--compiler/rustc_metadata/messages.ftl382
-rw-r--r--compiler/rustc_metadata/src/creader.rs46
-rw-r--r--compiler/rustc_metadata/src/dependency_format.rs31
-rw-r--r--compiler/rustc_metadata/src/errors.rs2
-rw-r--r--compiler/rustc_metadata/src/lib.rs2
-rw-r--r--compiler/rustc_metadata/src/locator.rs28
-rw-r--r--compiler/rustc_metadata/src/native_libs.rs20
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder.rs138
-rw-r--r--compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs21
-rw-r--r--compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs6
-rw-r--r--compiler/rustc_metadata/src/rmeta/encoder.rs98
-rw-r--r--compiler/rustc_metadata/src/rmeta/mod.rs25
-rw-r--r--compiler/rustc_metadata/src/rmeta/table.rs6
-rw-r--r--compiler/rustc_middle/Cargo.toml3
-rw-r--r--compiler/rustc_middle/messages.ftl43
-rw-r--r--compiler/rustc_middle/src/arena.rs11
-rw-r--r--compiler/rustc_middle/src/dep_graph/dep_node.rs7
-rw-r--r--compiler/rustc_middle/src/error.rs10
-rw-r--r--compiler/rustc_middle/src/hir/map/mod.rs35
-rw-r--r--compiler/rustc_middle/src/hir/mod.rs19
-rw-r--r--compiler/rustc_middle/src/hir/place.rs1
-rw-r--r--compiler/rustc_middle/src/infer/canonical.rs16
-rw-r--r--compiler/rustc_middle/src/lib.rs18
-rw-r--r--compiler/rustc_middle/src/lint.rs15
-rw-r--r--compiler/rustc_middle/src/macros.rs34
-rw-r--r--compiler/rustc_middle/src/metadata.rs3
-rw-r--r--compiler/rustc_middle/src/middle/debugger_visualizer.rs38
-rw-r--r--compiler/rustc_middle/src/middle/exported_symbols.rs2
-rw-r--r--compiler/rustc_middle/src/middle/lang_items.rs8
-rw-r--r--compiler/rustc_middle/src/middle/limits.rs4
-rw-r--r--compiler/rustc_middle/src/middle/mod.rs3
-rw-r--r--compiler/rustc_middle/src/middle/privacy.rs48
-rw-r--r--compiler/rustc_middle/src/middle/region.rs6
-rw-r--r--compiler/rustc_middle/src/middle/stability.rs10
-rw-r--r--compiler/rustc_middle/src/mir/basic_blocks.rs7
-rw-r--r--compiler/rustc_middle/src/mir/graphviz.rs23
-rw-r--r--compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs32
-rw-r--r--compiler/rustc_middle/src/mir/interpret/error.rs53
-rw-r--r--compiler/rustc_middle/src/mir/interpret/mod.rs8
-rw-r--r--compiler/rustc_middle/src/mir/interpret/pointer.rs2
-rw-r--r--compiler/rustc_middle/src/mir/interpret/queries.rs23
-rw-r--r--compiler/rustc_middle/src/mir/mod.rs177
-rw-r--r--compiler/rustc_middle/src/mir/mono.rs28
-rw-r--r--compiler/rustc_middle/src/mir/patch.rs2
-rw-r--r--compiler/rustc_middle/src/mir/pretty.rs22
-rw-r--r--compiler/rustc_middle/src/mir/query.rs45
-rw-r--r--compiler/rustc_middle/src/mir/syntax.rs50
-rw-r--r--compiler/rustc_middle/src/mir/tcx.rs4
-rw-r--r--compiler/rustc_middle/src/mir/type_foldable.rs6
-rw-r--r--compiler/rustc_middle/src/mir/visit.rs43
-rw-r--r--compiler/rustc_middle/src/query/erase.rs13
-rw-r--r--compiler/rustc_middle/src/query/keys.rs10
-rw-r--r--compiler/rustc_middle/src/query/mod.rs391
-rw-r--r--compiler/rustc_middle/src/query/on_disk_cache.rs (renamed from compiler/rustc_query_impl/src/on_disk_cache.rs)159
-rw-r--r--compiler/rustc_middle/src/query/plumbing.rs (renamed from compiler/rustc_middle/src/ty/query.rs)479
-rw-r--r--compiler/rustc_middle/src/thir.rs14
-rw-r--r--compiler/rustc_middle/src/thir/visit.rs1
-rw-r--r--compiler/rustc_middle/src/traits/mod.rs54
-rw-r--r--compiler/rustc_middle/src/traits/query.rs2
-rw-r--r--compiler/rustc_middle/src/traits/select.rs2
-rw-r--r--compiler/rustc_middle/src/traits/solve.rs71
-rw-r--r--compiler/rustc_middle/src/ty/_match.rs4
-rw-r--r--compiler/rustc_middle/src/ty/abstract_const.rs23
-rw-r--r--compiler/rustc_middle/src/ty/adt.rs30
-rw-r--r--compiler/rustc_middle/src/ty/closure.rs5
-rw-r--r--compiler/rustc_middle/src/ty/codec.rs31
-rw-r--r--compiler/rustc_middle/src/ty/consts.rs40
-rw-r--r--compiler/rustc_middle/src/ty/consts/int.rs10
-rw-r--r--compiler/rustc_middle/src/ty/consts/kind.rs19
-rw-r--r--compiler/rustc_middle/src/ty/context.rs244
-rw-r--r--compiler/rustc_middle/src/ty/context/tls.rs10
-rw-r--r--compiler/rustc_middle/src/ty/diagnostics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/erase_regions.rs7
-rw-r--r--compiler/rustc_middle/src/ty/error.rs6
-rw-r--r--compiler/rustc_middle/src/ty/fast_reject.rs2
-rw-r--r--compiler/rustc_middle/src/ty/flags.rs20
-rw-r--r--compiler/rustc_middle/src/ty/fold.rs3
-rw-r--r--compiler/rustc_middle/src/ty/generics.rs4
-rw-r--r--compiler/rustc_middle/src/ty/impls_ty.rs28
-rw-r--r--compiler/rustc_middle/src/ty/inhabitedness/mod.rs12
-rw-r--r--compiler/rustc_middle/src/ty/instance.rs121
-rw-r--r--compiler/rustc_middle/src/ty/layout.rs26
-rw-r--r--compiler/rustc_middle/src/ty/list.rs36
-rw-r--r--compiler/rustc_middle/src/ty/mod.rs328
-rw-r--r--compiler/rustc_middle/src/ty/normalize_erasing_regions.rs10
-rw-r--r--compiler/rustc_middle/src/ty/opaque_types.rs14
-rw-r--r--compiler/rustc_middle/src/ty/parameterized.rs4
-rw-r--r--compiler/rustc_middle/src/ty/print/mod.rs9
-rw-r--r--compiler/rustc_middle/src/ty/print/pretty.rs121
-rw-r--r--compiler/rustc_middle/src/ty/relate.rs52
-rw-r--r--compiler/rustc_middle/src/ty/structural_impls.rs87
-rw-r--r--compiler/rustc_middle/src/ty/sty.rs150
-rw-r--r--compiler/rustc_middle/src/ty/subst.rs139
-rw-r--r--compiler/rustc_middle/src/ty/trait_def.rs62
-rw-r--r--compiler/rustc_middle/src/ty/typeck_results.rs26
-rw-r--r--compiler/rustc_middle/src/ty/util.rs142
-rw-r--r--compiler/rustc_middle/src/ty/visit.rs25
-rw-r--r--compiler/rustc_middle/src/ty/walk.rs2
-rw-r--r--compiler/rustc_middle/src/util/bug.rs8
-rw-r--r--compiler/rustc_middle/src/util/call_kind.rs (renamed from compiler/rustc_const_eval/src/util/call_kind.rs)9
-rw-r--r--compiler/rustc_middle/src/util/find_self_call.rs (renamed from compiler/rustc_const_eval/src/util/find_self_call.rs)6
-rw-r--r--compiler/rustc_middle/src/util/mod.rs7
-rw-r--r--compiler/rustc_middle/src/values.rs10
-rw-r--r--compiler/rustc_mir_build/Cargo.toml1
-rw-r--r--compiler/rustc_mir_build/messages.ftl476
-rw-r--r--compiler/rustc_mir_build/src/build/block.rs4
-rw-r--r--compiler/rustc_mir_build/src/build/custom/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/custom/parse/instruction.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_constant.rs12
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_operand.rs8
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_place.rs1
-rw-r--r--compiler/rustc_mir_build/src/build/expr/as_rvalue.rs108
-rw-r--r--compiler/rustc_mir_build/src/build/expr/category.rs3
-rw-r--r--compiler/rustc_mir_build/src/build/expr/into.rs7
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs2
-rw-r--r--compiler/rustc_mir_build/src/build/matches/test.rs61
-rw-r--r--compiler/rustc_mir_build/src/build/mod.rs85
-rw-r--r--compiler/rustc_mir_build/src/build/scope.rs45
-rw-r--r--compiler/rustc_mir_build/src/check_unsafety.rs41
-rw-r--r--compiler/rustc_mir_build/src/errors.rs11
-rw-r--r--compiler/rustc_mir_build/src/lib.rs5
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/block.rs2
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs15
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/mod.rs25
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/check_match.rs119
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs71
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs10
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/mod.rs4
-rw-r--r--compiler/rustc_mir_build/src/thir/pattern/usefulness.rs19
-rw-r--r--compiler/rustc_mir_build/src/thir/print.rs17
-rw-r--r--compiler/rustc_mir_dataflow/Cargo.toml1
-rw-r--r--compiler/rustc_mir_dataflow/messages.ftl34
-rw-r--r--compiler/rustc_mir_dataflow/src/elaborate_drops.rs13
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/direction.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/engine.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/fmt.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/lattice.rs22
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/mod.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/framework/tests.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/liveness.rs1
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/mod.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs67
-rw-r--r--compiler/rustc_mir_dataflow/src/lib.rs2
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/builder.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/move_paths/mod.rs4
-rw-r--r--compiler/rustc_mir_dataflow/src/value_analysis.rs274
-rw-r--r--compiler/rustc_mir_transform/Cargo.toml2
-rw-r--r--compiler/rustc_mir_transform/messages.ftl67
-rw-r--r--compiler/rustc_mir_transform/src/add_call_guards.rs2
-rw-r--r--compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs13
-rw-r--r--compiler/rustc_mir_transform/src/add_retag.rs2
-rw-r--r--compiler/rustc_mir_transform/src/check_alignment.rs10
-rw-r--r--compiler/rustc_mir_transform/src/check_const_item_mutation.rs72
-rw-r--r--compiler/rustc_mir_transform/src/check_packed_ref.rs20
-rw-r--r--compiler/rustc_mir_transform/src/check_unsafety.rs102
-rw-r--r--compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs1
-rw-r--r--compiler/rustc_mir_transform/src/const_debuginfo.rs8
-rw-r--r--compiler/rustc_mir_transform/src/const_prop.rs112
-rw-r--r--compiler/rustc_mir_transform/src/const_prop_lint.rs84
-rw-r--r--compiler/rustc_mir_transform/src/copy_prop.rs37
-rw-r--r--compiler/rustc_mir_transform/src/coverage/debug.rs37
-rw-r--r--compiler/rustc_mir_transform/src/coverage/graph.rs33
-rw-r--r--compiler/rustc_mir_transform/src/coverage/mod.rs11
-rw-r--r--compiler/rustc_mir_transform/src/coverage/query.rs5
-rw-r--r--compiler/rustc_mir_transform/src/coverage/spans.rs5
-rw-r--r--compiler/rustc_mir_transform/src/coverage/tests.rs13
-rw-r--r--compiler/rustc_mir_transform/src/ctfe_limit.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dataflow_const_prop.rs163
-rw-r--r--compiler/rustc_mir_transform/src/dead_store_elimination.rs5
-rw-r--r--compiler/rustc_mir_transform/src/deduce_param_attrs.rs39
-rw-r--r--compiler/rustc_mir_transform/src/deref_separator.rs2
-rw-r--r--compiler/rustc_mir_transform/src/dest_prop.rs11
-rw-r--r--compiler/rustc_mir_transform/src/dump_mir.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_box_derefs.rs2
-rw-r--r--compiler/rustc_mir_transform/src/elaborate_drops.rs30
-rw-r--r--compiler/rustc_mir_transform/src/errors.rs245
-rw-r--r--compiler/rustc_mir_transform/src/ffi_unwind_calls.rs20
-rw-r--r--compiler/rustc_mir_transform/src/function_item_references.rs81
-rw-r--r--compiler/rustc_mir_transform/src/generator.rs64
-rw-r--r--compiler/rustc_mir_transform/src/inline.rs139
-rw-r--r--compiler/rustc_mir_transform/src/inline/cycle.rs13
-rw-r--r--compiler/rustc_mir_transform/src/instsimplify.rs (renamed from compiler/rustc_mir_transform/src/instcombine.rs)80
-rw-r--r--compiler/rustc_mir_transform/src/large_enums.rs2
-rw-r--r--compiler/rustc_mir_transform/src/lib.rs217
-rw-r--r--compiler/rustc_mir_transform/src/lower_intrinsics.rs52
-rw-r--r--compiler/rustc_mir_transform/src/lower_slice_len.rs2
-rw-r--r--compiler/rustc_mir_transform/src/match_branches.rs2
-rw-r--r--compiler/rustc_mir_transform/src/normalize_array_len.rs9
-rw-r--r--compiler/rustc_mir_transform/src/nrvo.rs5
-rw-r--r--compiler/rustc_mir_transform/src/pass_manager.rs8
-rw-r--r--compiler/rustc_mir_transform/src/ref_prop.rs408
-rw-r--r--compiler/rustc_mir_transform/src/remove_place_mention.rs23
-rw-r--r--compiler/rustc_mir_transform/src/reveal_all.rs14
-rw-r--r--compiler/rustc_mir_transform/src/separate_const_switch.rs3
-rw-r--r--compiler/rustc_mir_transform/src/shim.rs13
-rw-r--r--compiler/rustc_mir_transform/src/simplify.rs66
-rw-r--r--compiler/rustc_mir_transform/src/simplify_branches.rs23
-rw-r--r--compiler/rustc_mir_transform/src/simplify_comparison_integral.rs2
-rw-r--r--compiler/rustc_mir_transform/src/sroa.rs2
-rw-r--r--compiler/rustc_mir_transform/src/ssa.rs260
-rw-r--r--compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs4
-rw-r--r--compiler/rustc_monomorphize/Cargo.toml2
-rw-r--r--compiler/rustc_monomorphize/messages.ftl34
-rw-r--r--compiler/rustc_monomorphize/src/collector.rs10
-rw-r--r--compiler/rustc_monomorphize/src/lib.rs12
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/default.rs170
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/merging.rs111
-rw-r--r--compiler/rustc_monomorphize/src/partitioning/mod.rs197
-rw-r--r--compiler/rustc_monomorphize/src/polymorphize.rs12
-rw-r--r--compiler/rustc_monomorphize/src/util.rs4
-rw-r--r--compiler/rustc_parse/Cargo.toml1
-rw-r--r--compiler/rustc_parse/messages.ftl1097
-rw-r--r--compiler/rustc_parse/src/errors.rs399
-rw-r--r--compiler/rustc_parse/src/lexer/mod.rs77
-rw-r--r--compiler/rustc_parse/src/lexer/tokentrees.rs3
-rw-r--r--compiler/rustc_parse/src/lexer/unescape_error_reporting.rs33
-rw-r--r--compiler/rustc_parse/src/lexer/unicode_chars.rs2
-rw-r--r--compiler/rustc_parse/src/lib.rs25
-rw-r--r--compiler/rustc_parse/src/parser/attr.rs6
-rw-r--r--compiler/rustc_parse/src/parser/attr_wrapper.rs2
-rw-r--r--compiler/rustc_parse/src/parser/diagnostics.rs178
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs197
-rw-r--r--compiler/rustc_parse/src/parser/generics.rs46
-rw-r--r--compiler/rustc_parse/src/parser/item.rs222
-rw-r--r--compiler/rustc_parse/src/parser/mod.rs39
-rw-r--r--compiler/rustc_parse/src/parser/nonterminal.rs10
-rw-r--r--compiler/rustc_parse/src/parser/pat.rs37
-rw-r--r--compiler/rustc_parse/src/parser/path.rs113
-rw-r--r--compiler/rustc_parse/src/parser/stmt.rs137
-rw-r--r--compiler/rustc_parse/src/parser/ty.rs204
-rw-r--r--compiler/rustc_parse/src/validate_attr.rs33
-rw-r--r--compiler/rustc_passes/Cargo.toml1
-rw-r--r--compiler/rustc_passes/messages.ftl1051
-rw-r--r--compiler/rustc_passes/src/check_attr.rs111
-rw-r--r--compiler/rustc_passes/src/check_const.rs6
-rw-r--r--compiler/rustc_passes/src/dead.rs36
-rw-r--r--compiler/rustc_passes/src/debugger_visualizer.rs127
-rw-r--r--compiler/rustc_passes/src/diagnostic_items.rs2
-rw-r--r--compiler/rustc_passes/src/entry.rs2
-rw-r--r--compiler/rustc_passes/src/errors.rs164
-rw-r--r--compiler/rustc_passes/src/hir_id_validator.rs2
-rw-r--r--compiler/rustc_passes/src/hir_stats.rs5
-rw-r--r--compiler/rustc_passes/src/lang_items.rs2
-rw-r--r--compiler/rustc_passes/src/lib.rs6
-rw-r--r--compiler/rustc_passes/src/lib_features.rs2
-rw-r--r--compiler/rustc_passes/src/liveness.rs242
-rw-r--r--compiler/rustc_passes/src/loops.rs2
-rw-r--r--compiler/rustc_passes/src/naked_functions.rs3
-rw-r--r--compiler/rustc_passes/src/reachable.rs2
-rw-r--r--compiler/rustc_passes/src/stability.rs68
-rw-r--r--compiler/rustc_passes/src/upvars.rs2
-rw-r--r--compiler/rustc_plugin_impl/Cargo.toml1
-rw-r--r--compiler/rustc_plugin_impl/src/lib.rs2
-rw-r--r--compiler/rustc_privacy/Cargo.toml1
-rw-r--r--compiler/rustc_privacy/messages.ftl18
-rw-r--r--compiler/rustc_privacy/src/lib.rs473
-rw-r--r--compiler/rustc_query_impl/Cargo.toml2
-rw-r--r--compiler/rustc_query_impl/src/lib.rs213
-rw-r--r--compiler/rustc_query_impl/src/plumbing.rs670
-rw-r--r--compiler/rustc_query_impl/src/profiling_support.rs53
-rw-r--r--compiler/rustc_query_system/Cargo.toml2
-rw-r--r--compiler/rustc_query_system/messages.ftl30
-rw-r--r--compiler/rustc_query_system/src/dep_graph/graph.rs106
-rw-r--r--compiler/rustc_query_system/src/dep_graph/query.rs7
-rw-r--r--compiler/rustc_query_system/src/dep_graph/serialized.rs18
-rw-r--r--compiler/rustc_query_system/src/ich/impls_syntax.rs6
-rw-r--r--compiler/rustc_query_system/src/lib.rs2
-rw-r--r--compiler/rustc_query_system/src/query/caches.rs2
-rw-r--r--compiler/rustc_query_system/src/query/config.rs13
-rw-r--r--compiler/rustc_query_system/src/query/job.rs6
-rw-r--r--compiler/rustc_query_system/src/query/mod.rs7
-rw-r--r--compiler/rustc_query_system/src/query/plumbing.rs164
-rw-r--r--compiler/rustc_resolve/Cargo.toml3
-rw-r--r--compiler/rustc_resolve/messages.ftl329
-rw-r--r--compiler/rustc_resolve/src/build_reduced_graph.rs45
-rw-r--r--compiler/rustc_resolve/src/check_unused.rs17
-rw-r--r--compiler/rustc_resolve/src/diagnostics.rs123
-rw-r--r--compiler/rustc_resolve/src/effective_visibilities.rs6
-rw-r--r--compiler/rustc_resolve/src/errors.rs88
-rw-r--r--compiler/rustc_resolve/src/ident.rs202
-rw-r--r--compiler/rustc_resolve/src/imports.rs54
-rw-r--r--compiler/rustc_resolve/src/late.rs497
-rw-r--r--compiler/rustc_resolve/src/late/diagnostics.rs278
-rw-r--r--compiler/rustc_resolve/src/lib.rs44
-rw-r--r--compiler/rustc_resolve/src/macros.rs39
-rw-r--r--compiler/rustc_resolve/src/rustdoc.rs1
-rw-r--r--compiler/rustc_serialize/Cargo.toml1
-rw-r--r--compiler/rustc_serialize/src/leb128.rs16
-rw-r--r--compiler/rustc_serialize/src/lib.rs1
-rw-r--r--compiler/rustc_serialize/src/opaque.rs503
-rw-r--r--compiler/rustc_serialize/src/serialize.rs79
-rw-r--r--compiler/rustc_serialize/tests/leb128.rs13
-rw-r--r--compiler/rustc_serialize/tests/opaque.rs56
-rw-r--r--compiler/rustc_session/Cargo.toml4
-rw-r--r--compiler/rustc_session/messages.ftl116
-rw-r--r--compiler/rustc_session/src/config.rs335
-rw-r--r--compiler/rustc_session/src/cstore.rs11
-rw-r--r--compiler/rustc_session/src/errors.rs35
-rw-r--r--compiler/rustc_session/src/filesearch.rs4
-rw-r--r--compiler/rustc_session/src/lib.rs2
-rw-r--r--compiler/rustc_session/src/options.rs33
-rw-r--r--compiler/rustc_session/src/parse.rs7
-rw-r--r--compiler/rustc_session/src/session.rs116
-rw-r--r--compiler/rustc_smir/Cargo.toml1
-rw-r--r--compiler/rustc_smir/src/lib.rs2
-rw-r--r--compiler/rustc_smir/src/rustc_internal/mod.rs45
-rw-r--r--compiler/rustc_smir/src/rustc_smir/mod.rs283
-rw-r--r--compiler/rustc_smir/src/stable_mir/mir/body.rs83
-rw-r--r--compiler/rustc_smir/src/stable_mir/mod.rs66
-rw-r--r--compiler/rustc_smir/src/stable_mir/ty.rs15
-rw-r--r--compiler/rustc_span/src/def_id.rs50
-rw-r--r--compiler/rustc_span/src/hygiene.rs22
-rw-r--r--compiler/rustc_span/src/lib.rs119
-rw-r--r--compiler/rustc_span/src/source_map.rs28
-rw-r--r--compiler/rustc_span/src/span_encoding.rs24
-rw-r--r--compiler/rustc_span/src/symbol.rs29
-rw-r--r--compiler/rustc_span/src/tests.rs8
-rw-r--r--compiler/rustc_symbol_mangling/Cargo.toml1
-rw-r--r--compiler/rustc_symbol_mangling/src/legacy.rs14
-rw-r--r--compiler/rustc_symbol_mangling/src/lib.rs4
-rw-r--r--compiler/rustc_symbol_mangling/src/test.rs2
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid.rs91
-rw-r--r--compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs338
-rw-r--r--compiler/rustc_symbol_mangling/src/v0.rs5
-rw-r--r--compiler/rustc_target/Cargo.toml1
-rw-r--r--compiler/rustc_target/src/abi/call/avr.rs2
-rw-r--r--compiler/rustc_target/src/abi/call/mod.rs10
-rw-r--r--compiler/rustc_target/src/abi/mod.rs15
-rw-r--r--compiler/rustc_target/src/asm/loongarch.rs130
-rw-r--r--compiler/rustc_target/src/asm/mod.rs46
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_darwin.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs7
-rw-r--r--compiler/rustc_target/src/spec/abi.rs53
-rw-r--r--compiler/rustc_target/src/spec/apple_base.rs63
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs4
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/armv7r_none_eabihf.rs2
-rw-r--r--compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs1
-rw-r--r--compiler/rustc_target/src/spec/mod.rs8
-rw-r--r--compiler/rustc_target/src/spec/thumb_base.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs2
-rw-r--r--compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs44
-rw-r--r--compiler/rustc_trait_selection/Cargo.toml2
-rw-r--r--compiler/rustc_trait_selection/messages.ftl14
-rw-r--r--compiler/rustc_trait_selection/src/errors.rs8
-rw-r--r--compiler/rustc_trait_selection/src/infer.rs14
-rw-r--r--compiler/rustc_trait_selection/src/lib.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/mod.rs188
-rw-r--r--compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs11
-rw-r--r--compiler/rustc_trait_selection/src/solve/canonicalize.rs2
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt.rs144
-rw-r--r--compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs128
-rw-r--r--compiler/rustc_trait_selection/src/solve/fulfill.rs4
-rw-r--r--compiler/rustc_trait_selection/src/solve/mod.rs99
-rw-r--r--compiler/rustc_trait_selection/src/solve/opaques.rs67
-rw-r--r--compiler/rustc_trait_selection/src/solve/project_goals.rs120
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/cache.rs8
-rw-r--r--compiler/rustc_trait_selection/src/solve/search_graph/mod.rs56
-rw-r--r--compiler/rustc_trait_selection/src/solve/trait_goals.rs168
-rw-r--r--compiler/rustc_trait_selection/src/traits/auto_trait.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/coherence.rs13
-rw-r--r--compiler/rustc_trait_selection/src/traits/const_evaluatable.rs8
-rw-r--r--compiler/rustc_trait_selection/src/traits/engine.rs6
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs2
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs102
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs1382
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs34
-rw-r--r--compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs545
-rw-r--r--compiler/rustc_trait_selection/src/traits/fulfill.rs5
-rw-r--r--compiler/rustc_trait_selection/src/traits/misc.rs103
-rw-r--r--compiler/rustc_trait_selection/src/traits/mod.rs65
-rw-r--r--compiler/rustc_trait_selection/src/traits/object_safety.rs43
-rw-r--r--compiler/rustc_trait_selection/src/traits/outlives_bounds.rs54
-rw-r--r--compiler/rustc_trait_selection/src/traits/project.rs232
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs269
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/normalize.rs17
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs123
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs68
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs181
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs68
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs24
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs16
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs28
-rw-r--r--compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs14
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs50
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/confirmation.rs138
-rw-r--r--compiler/rustc_trait_selection/src/traits/select/mod.rs89
-rw-r--r--compiler/rustc_trait_selection/src/traits/specialize/mod.rs71
-rw-r--r--compiler/rustc_trait_selection/src/traits/structural_normalize.rs55
-rw-r--r--compiler/rustc_trait_selection/src/traits/util.rs19
-rw-r--r--compiler/rustc_trait_selection/src/traits/vtable.rs11
-rw-r--r--compiler/rustc_trait_selection/src/traits/wf.rs135
-rw-r--r--compiler/rustc_traits/Cargo.toml1
-rw-r--r--compiler/rustc_traits/src/chalk/db.rs19
-rw-r--r--compiler/rustc_traits/src/chalk/lowering.rs31
-rw-r--r--compiler/rustc_traits/src/chalk/mod.rs2
-rw-r--r--compiler/rustc_traits/src/codegen.rs4
-rw-r--r--compiler/rustc_traits/src/dropck_outlives.rs268
-rw-r--r--compiler/rustc_traits/src/evaluate_obligation.rs6
-rw-r--r--compiler/rustc_traits/src/implied_outlives_bounds.rs173
-rw-r--r--compiler/rustc_traits/src/lib.rs5
-rw-r--r--compiler/rustc_traits/src/normalize_erasing_regions.rs4
-rw-r--r--compiler/rustc_traits/src/normalize_projection_ty.rs31
-rw-r--r--compiler/rustc_traits/src/type_op.rs124
-rw-r--r--compiler/rustc_transmute/src/layout/tree.rs2
-rw-r--r--compiler/rustc_transmute/src/lib.rs13
-rw-r--r--compiler/rustc_ty_utils/Cargo.toml1
-rw-r--r--compiler/rustc_ty_utils/messages.ftl62
-rw-r--r--compiler/rustc_ty_utils/src/abi.rs40
-rw-r--r--compiler/rustc_ty_utils/src/assoc.rs7
-rw-r--r--compiler/rustc_ty_utils/src/common_traits.rs11
-rw-r--r--compiler/rustc_ty_utils/src/consts.rs77
-rw-r--r--compiler/rustc_ty_utils/src/errors.rs24
-rw-r--r--compiler/rustc_ty_utils/src/implied_bounds.rs18
-rw-r--r--compiler/rustc_ty_utils/src/instance.rs149
-rw-r--r--compiler/rustc_ty_utils/src/layout.rs7
-rw-r--r--compiler/rustc_ty_utils/src/layout_sanity_check.rs96
-rw-r--r--compiler/rustc_ty_utils/src/lib.rs7
-rw-r--r--compiler/rustc_ty_utils/src/needs_drop.rs9
-rw-r--r--compiler/rustc_ty_utils/src/opaque_types.rs198
-rw-r--r--compiler/rustc_ty_utils/src/representability.rs2
-rw-r--r--compiler/rustc_ty_utils/src/structural_match.rs4
-rw-r--r--compiler/rustc_ty_utils/src/ty.rs10
-rw-r--r--compiler/rustc_type_ir/src/codec.rs7
-rw-r--r--compiler/rustc_type_ir/src/fold.rs37
-rw-r--r--compiler/rustc_type_ir/src/lib.rs39
-rw-r--r--compiler/rustc_type_ir/src/macros.rs141
-rw-r--r--compiler/rustc_type_ir/src/structural_impls.rs76
-rw-r--r--compiler/rustc_type_ir/src/sty.rs11
-rw-r--r--compiler/rustc_type_ir/src/visit.rs28
984 files changed, 32456 insertions, 24287 deletions
diff --git a/compiler/rustc_abi/src/layout.rs b/compiler/rustc_abi/src/layout.rs
index c863acde7..73f9deb31 100644
--- a/compiler/rustc_abi/src/layout.rs
+++ b/compiler/rustc_abi/src/layout.rs
@@ -1,4 +1,5 @@
use super::*;
+use std::fmt::Write;
use std::{borrow::Borrow, cmp, iter, ops::Bound};
#[cfg(feature = "randomize")]
@@ -11,7 +12,7 @@ use tracing::debug;
pub trait LayoutCalculator {
type TargetDataLayoutRef: Borrow<TargetDataLayout>;
- fn delay_bug(&self, txt: &str);
+ fn delay_bug(&self, txt: String);
fn current_data_layout(&self) -> Self::TargetDataLayoutRef;
fn scalar_pair(&self, a: Scalar, b: Scalar) -> LayoutS {
@@ -49,219 +50,66 @@ pub trait LayoutCalculator {
repr: &ReprOptions,
kind: StructKind,
) -> Option<LayoutS> {
- let pack = repr.pack;
- let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
- let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
- let optimize = !repr.inhibit_struct_field_reordering_opt();
- if optimize {
- let end =
- if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
- let optimizing = &mut inverse_memory_index.raw[..end];
- let effective_field_align = |layout: Layout<'_>| {
- if let Some(pack) = pack {
- // return the packed alignment in bytes
- layout.align().abi.min(pack).bytes()
- } else {
- // returns log2(effective-align).
- // This is ok since `pack` applies to all fields equally.
- // The calculation assumes that size is an integer multiple of align, except for ZSTs.
- //
- // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
- layout.align().abi.bytes().max(layout.size().bytes()).trailing_zeros() as u64
- }
- };
-
- // If `-Z randomize-layout` was enabled for the type definition we can shuffle
- // the field ordering to try and catch some code making assumptions about layouts
- // we don't guarantee
- if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
- #[cfg(feature = "randomize")]
- {
- // `ReprOptions.layout_seed` is a deterministic seed that we can use to
- // randomize field ordering with
- let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed);
-
- // Shuffle the ordering of the fields
- optimizing.shuffle(&mut rng);
- }
- // Otherwise we just leave things alone and actually optimize the type's fields
- } else {
- match kind {
- StructKind::AlwaysSized | StructKind::MaybeUnsized => {
- optimizing.sort_by_key(|&x| {
- // Place ZSTs first to avoid "interesting offsets",
- // especially with only one or two non-ZST fields.
- // Then place largest alignments first, largest niches within an alignment group last
- let f = fields[x];
- let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
- (!f.0.is_zst(), cmp::Reverse(effective_field_align(f)), niche_size)
- });
- }
-
- StructKind::Prefixed(..) => {
- // Sort in ascending alignment so that the layout stays optimal
- // regardless of the prefix.
- // And put the largest niche in an alignment group at the end
- // so it can be used as discriminant in jagged enums
- optimizing.sort_by_key(|&x| {
- let f = fields[x];
- let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
- (effective_field_align(f), niche_size)
- });
- }
- }
-
- // FIXME(Kixiron): We can always shuffle fields within a given alignment class
- // regardless of the status of `-Z randomize-layout`
- }
- }
- // inverse_memory_index holds field indices by increasing memory offset.
- // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
- // We now write field offsets to the corresponding offset slot;
- // field 5 with offset 0 puts 0 in offsets[5].
- // At the bottom of this function, we invert `inverse_memory_index` to
- // produce `memory_index` (see `invert_mapping`).
- let mut sized = true;
- let mut offsets = IndexVec::from_elem(Size::ZERO, &fields);
- let mut offset = Size::ZERO;
- let mut largest_niche = None;
- let mut largest_niche_available = 0;
- if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
- let prefix_align =
- if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align };
- align = align.max(AbiAndPrefAlign::new(prefix_align));
- offset = prefix_size.align_to(prefix_align);
- }
- for &i in &inverse_memory_index {
- let field = &fields[i];
- if !sized {
- self.delay_bug(&format!(
- "univariant: field #{} comes after unsized field",
- offsets.len(),
- ));
- }
-
- if field.0.is_unsized() {
- sized = false;
- }
-
- // Invariant: offset < dl.obj_size_bound() <= 1<<61
- let field_align = if let Some(pack) = pack {
- field.align().min(AbiAndPrefAlign::new(pack))
- } else {
- field.align()
- };
- offset = offset.align_to(field_align.abi);
- align = align.max(field_align);
-
- debug!("univariant offset: {:?} field: {:#?}", offset, field);
- offsets[i] = offset;
-
- if let Some(mut niche) = field.largest_niche() {
- let available = niche.available(dl);
- if available > largest_niche_available {
- largest_niche_available = available;
- niche.offset += offset;
- largest_niche = Some(niche);
- }
- }
-
- offset = offset.checked_add(field.size(), dl)?;
- }
- if let Some(repr_align) = repr.align {
- align = align.max(AbiAndPrefAlign::new(repr_align));
- }
- debug!("univariant min_size: {:?}", offset);
- let min_size = offset;
- // As stated above, inverse_memory_index holds field indices by increasing offset.
- // This makes it an already-sorted view of the offsets vec.
- // To invert it, consider:
- // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
- // Field 5 would be the first element, so memory_index is i:
- // Note: if we didn't optimize, it's already right.
- let memory_index = if optimize {
- inverse_memory_index.invert_bijective_mapping()
- } else {
- debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
- inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
- };
- let size = min_size.align_to(align.abi);
- let mut abi = Abi::Aggregate { sized };
- // Unpack newtype ABIs and find scalar pairs.
- if sized && size.bytes() > 0 {
- // All other fields must be ZSTs.
- let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
-
- match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
- // We have exactly one non-ZST field.
- (Some((i, field)), None, None) => {
- // Field fills the struct and it has a scalar or scalar pair ABI.
- if offsets[i].bytes() == 0
- && align.abi == field.align().abi
- && size == field.size()
- {
- match field.abi() {
- // For plain scalars, or vectors of them, we can't unpack
- // newtypes for `#[repr(C)]`, as that affects C ABIs.
- Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
- abi = field.abi();
- }
- // But scalar pairs are Rust-specific and get
- // treated as aggregates by C ABIs anyway.
- Abi::ScalarPair(..) => {
- abi = field.abi();
- }
- _ => {}
- }
- }
- }
-
- // Two non-ZST fields, and they're both scalars.
- (Some((i, a)), Some((j, b)), None) => {
- match (a.abi(), b.abi()) {
- (Abi::Scalar(a), Abi::Scalar(b)) => {
- // Order by the memory placement, not source order.
- let ((i, a), (j, b)) = if offsets[i] < offsets[j] {
- ((i, a), (j, b))
- } else {
- ((j, b), (i, a))
- };
- let pair = self.scalar_pair(a, b);
- let pair_offsets = match pair.fields {
- FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
- assert_eq!(memory_index.raw, [0, 1]);
- offsets
- }
- _ => panic!(),
- };
- if offsets[i] == pair_offsets[FieldIdx::from_usize(0)]
- && offsets[j] == pair_offsets[FieldIdx::from_usize(1)]
- && align == pair.align
- && size == pair.size
- {
- // We can use `ScalarPair` only when it matches our
- // already computed layout (including `#[repr(C)]`).
- abi = pair.abi;
- }
+ let layout = univariant(self, dl, fields, repr, kind, NicheBias::Start);
+ // Enums prefer niches close to the beginning or the end of the variants so that other (smaller)
+ // data-carrying variants can be packed into the space after/before the niche.
+ // If the default field ordering does not give us a niche at the front then we do a second
+ // run and bias niches to the right and then check which one is closer to one of the struct's
+ // edges.
+ if let Some(layout) = &layout {
+ // Don't try to calculate an end-biased layout for unsizable structs,
+ // otherwise we could end up with different layouts for
+ // Foo<Type> and Foo<dyn Trait> which would break unsizing
+ if !matches!(kind, StructKind::MaybeUnsized) {
+ if let Some(niche) = layout.largest_niche {
+ let head_space = niche.offset.bytes();
+ let niche_length = niche.value.size(dl).bytes();
+ let tail_space = layout.size.bytes() - head_space - niche_length;
+
+ // This may end up doing redundant work if the niche is already in the last field
+ // (e.g. a trailing bool) and there is tail padding. But it's non-trivial to get
+ // the unpadded size so we try anyway.
+ if fields.len() > 1 && head_space != 0 && tail_space > 0 {
+ let alt_layout = univariant(self, dl, fields, repr, kind, NicheBias::End)
+ .expect("alt layout should always work");
+ let niche = alt_layout
+ .largest_niche
+ .expect("alt layout should have a niche like the regular one");
+ let alt_head_space = niche.offset.bytes();
+ let alt_niche_len = niche.value.size(dl).bytes();
+ let alt_tail_space =
+ alt_layout.size.bytes() - alt_head_space - alt_niche_len;
+
+ debug_assert_eq!(layout.size.bytes(), alt_layout.size.bytes());
+
+ let prefer_alt_layout =
+ alt_head_space > head_space && alt_head_space > tail_space;
+
+ debug!(
+ "sz: {}, default_niche_at: {}+{}, default_tail_space: {}, alt_niche_at/head_space: {}+{}, alt_tail: {}, num_fields: {}, better: {}\n\
+ layout: {}\n\
+ alt_layout: {}\n",
+ layout.size.bytes(),
+ head_space,
+ niche_length,
+ tail_space,
+ alt_head_space,
+ alt_niche_len,
+ alt_tail_space,
+ layout.fields.count(),
+ prefer_alt_layout,
+ format_field_niches(&layout, &fields, &dl),
+ format_field_niches(&alt_layout, &fields, &dl),
+ );
+
+ if prefer_alt_layout {
+ return Some(alt_layout);
}
- _ => {}
}
}
-
- _ => {}
}
}
- if fields.iter().any(|f| f.abi().is_uninhabited()) {
- abi = Abi::Uninhabited;
- }
- Some(LayoutS {
- variants: Variants::Single { index: FIRST_VARIANT },
- fields: FieldsShape::Arbitrary { offsets, memory_index },
- abi,
- largest_niche,
- align,
- size,
- })
+ layout
}
fn layout_of_never_type(&self) -> LayoutS {
@@ -461,8 +309,8 @@ pub trait LayoutCalculator {
let all_indices = variants.indices();
let needs_disc =
|index: VariantIdx| index != largest_variant_index && !absent(&variants[index]);
- let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap().index()
- ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap().index();
+ let niche_variants = all_indices.clone().find(|v| needs_disc(*v)).unwrap()
+ ..=all_indices.rev().find(|v| needs_disc(*v)).unwrap();
let count = niche_variants.size_hint().1.unwrap() as u128;
@@ -560,8 +408,7 @@ pub trait LayoutCalculator {
tag: niche_scalar,
tag_encoding: TagEncoding::Niche {
untagged_variant: largest_variant_index,
- niche_variants: (VariantIdx::new(*niche_variants.start())
- ..=VariantIdx::new(*niche_variants.end())),
+ niche_variants,
niche_start,
},
tag_field: 0,
@@ -888,42 +735,73 @@ pub trait LayoutCalculator {
align = align.max(AbiAndPrefAlign::new(repr_align));
}
- let optimize = !repr.inhibit_union_abi_opt();
+ // If all the non-ZST fields have the same ABI and union ABI optimizations aren't
+ // disabled, we can use that common ABI for the union as a whole.
+ struct AbiMismatch;
+ let mut common_non_zst_abi_and_align = if repr.inhibit_union_abi_opt() {
+ // Can't optimize
+ Err(AbiMismatch)
+ } else {
+ Ok(None)
+ };
+
let mut size = Size::ZERO;
- let mut abi = Abi::Aggregate { sized: true };
let only_variant = &variants[FIRST_VARIANT];
for field in only_variant {
assert!(field.0.is_sized());
+
align = align.max(field.align());
+ size = cmp::max(size, field.size());
+
+ if field.0.is_zst() {
+ // Nothing more to do for ZST fields
+ continue;
+ }
- // If all non-ZST fields have the same ABI, forward this ABI
- if optimize && !field.0.is_zst() {
+ if let Ok(common) = common_non_zst_abi_and_align {
// Discard valid range information and allow undef
- let field_abi = match field.abi() {
- Abi::Scalar(x) => Abi::Scalar(x.to_union()),
- Abi::ScalarPair(x, y) => Abi::ScalarPair(x.to_union(), y.to_union()),
- Abi::Vector { element: x, count } => {
- Abi::Vector { element: x.to_union(), count }
+ let field_abi = field.abi().to_union();
+
+ if let Some((common_abi, common_align)) = common {
+ if common_abi != field_abi {
+ // Different fields have different ABI: disable opt
+ common_non_zst_abi_and_align = Err(AbiMismatch);
+ } else {
+ // Fields with the same non-Aggregate ABI should also
+ // have the same alignment
+ if !matches!(common_abi, Abi::Aggregate { .. }) {
+ assert_eq!(
+ common_align,
+ field.align().abi,
+ "non-Aggregate field with matching ABI but differing alignment"
+ );
+ }
}
- Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
- };
-
- if size == Size::ZERO {
- // first non ZST: initialize 'abi'
- abi = field_abi;
- } else if abi != field_abi {
- // different fields have different ABI: reset to Aggregate
- abi = Abi::Aggregate { sized: true };
+ } else {
+ // First non-ZST field: record its ABI and alignment
+ common_non_zst_abi_and_align = Ok(Some((field_abi, field.align().abi)));
}
}
-
- size = cmp::max(size, field.size());
}
if let Some(pack) = repr.pack {
align = align.min(AbiAndPrefAlign::new(pack));
}
+ // If all non-ZST fields have the same ABI, we may forward that ABI
+ // for the union as a whole, unless otherwise inhibited.
+ let abi = match common_non_zst_abi_and_align {
+ Err(AbiMismatch) | Ok(None) => Abi::Aggregate { sized: true },
+ Ok(Some((abi, _))) => {
+ if abi.inherent_align(dl).map(|a| a.abi) != Some(align.abi) {
+ // Mismatched alignment (e.g. union is #[repr(packed)]): disable opt
+ Abi::Aggregate { sized: true }
+ } else {
+ abi
+ }
+ }
+ };
+
Some(LayoutS {
variants: Variants::Single { index: FIRST_VARIANT },
fields: FieldsShape::Union(NonZeroUsize::new(only_variant.len())?),
@@ -934,3 +812,327 @@ pub trait LayoutCalculator {
})
}
}
+
+/// Determines towards which end of a struct layout optimizations will try to place the best niches.
+enum NicheBias {
+ Start,
+ End,
+}
+
+fn univariant(
+ this: &(impl LayoutCalculator + ?Sized),
+ dl: &TargetDataLayout,
+ fields: &IndexSlice<FieldIdx, Layout<'_>>,
+ repr: &ReprOptions,
+ kind: StructKind,
+ niche_bias: NicheBias,
+) -> Option<LayoutS> {
+ let pack = repr.pack;
+ let mut align = if pack.is_some() { dl.i8_align } else { dl.aggregate_align };
+ let mut inverse_memory_index: IndexVec<u32, FieldIdx> = fields.indices().collect();
+ let optimize = !repr.inhibit_struct_field_reordering_opt();
+ if optimize && fields.len() > 1 {
+ let end = if let StructKind::MaybeUnsized = kind { fields.len() - 1 } else { fields.len() };
+ let optimizing = &mut inverse_memory_index.raw[..end];
+ let fields_excluding_tail = &fields.raw[..end];
+
+ // If `-Z randomize-layout` was enabled for the type definition we can shuffle
+ // the field ordering to try and catch some code making assumptions about layouts
+ // we don't guarantee
+ if repr.can_randomize_type_layout() && cfg!(feature = "randomize") {
+ #[cfg(feature = "randomize")]
+ {
+ // `ReprOptions.layout_seed` is a deterministic seed that we can use to
+ // randomize field ordering with
+ let mut rng = Xoshiro128StarStar::seed_from_u64(repr.field_shuffle_seed.as_u64());
+
+ // Shuffle the ordering of the fields
+ optimizing.shuffle(&mut rng);
+ }
+ // Otherwise we just leave things alone and actually optimize the type's fields
+ } else {
+ // To allow unsizing `&Foo<Type>` -> `&Foo<dyn Trait>`, the layout of the struct must
+ // not depend on the layout of the tail.
+ let max_field_align =
+ fields_excluding_tail.iter().map(|f| f.align().abi.bytes()).max().unwrap_or(1);
+ let largest_niche_size = fields_excluding_tail
+ .iter()
+ .filter_map(|f| f.largest_niche())
+ .map(|n| n.available(dl))
+ .max()
+ .unwrap_or(0);
+
+ // Calculates a sort key to group fields by their alignment or possibly some size-derived
+ // pseudo-alignment.
+ let alignment_group_key = |layout: Layout<'_>| {
+ if let Some(pack) = pack {
+ // return the packed alignment in bytes
+ layout.align().abi.min(pack).bytes()
+ } else {
+ // returns log2(effective-align).
+ // This is ok since `pack` applies to all fields equally.
+ // The calculation assumes that size is an integer multiple of align, except for ZSTs.
+ //
+ let align = layout.align().abi.bytes();
+ let size = layout.size().bytes();
+ let niche_size = layout.largest_niche().map(|n| n.available(dl)).unwrap_or(0);
+ // group [u8; 4] with align-4 or [u8; 6] with align-2 fields
+ let size_as_align = align.max(size).trailing_zeros();
+ let size_as_align = if largest_niche_size > 0 {
+ match niche_bias {
+ // Given `A(u8, [u8; 16])` and `B(bool, [u8; 16])` we want to bump the array
+ // to the front in the first case (for aligned loads) but keep the bool in front
+ // in the second case for its niches.
+ NicheBias::Start => max_field_align.trailing_zeros().min(size_as_align),
+ // When moving niches towards the end of the struct then for
+ // A((u8, u8, u8, bool), (u8, bool, u8)) we want to keep the first tuple
+ // in the align-1 group because its bool can be moved closer to the end.
+ NicheBias::End if niche_size == largest_niche_size => {
+ align.trailing_zeros()
+ }
+ NicheBias::End => size_as_align,
+ }
+ } else {
+ size_as_align
+ };
+ size_as_align as u64
+ }
+ };
+
+ match kind {
+ StructKind::AlwaysSized | StructKind::MaybeUnsized => {
+ // Currently `LayoutS` only exposes a single niche so sorting is usually sufficient
+ // to get one niche into the preferred position. If it ever supported multiple niches
+ // then a more advanced pick-and-pack approach could provide better results.
+ // But even for the single-niche cache it's not optimal. E.g. for
+ // A(u32, (bool, u8), u16) it would be possible to move the bool to the front
+ // but it would require packing the tuple together with the u16 to build a 4-byte
+ // group so that the u32 can be placed after it without padding. This kind
+ // of packing can't be achieved by sorting.
+ optimizing.sort_by_key(|&x| {
+ let f = fields[x];
+ let field_size = f.size().bytes();
+ let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
+ let niche_size_key = match niche_bias {
+ // large niche first
+ NicheBias::Start => !niche_size,
+ // large niche last
+ NicheBias::End => niche_size,
+ };
+ let inner_niche_offset_key = match niche_bias {
+ NicheBias::Start => f.largest_niche().map_or(0, |n| n.offset.bytes()),
+ NicheBias::End => f.largest_niche().map_or(0, |n| {
+ !(field_size - n.value.size(dl).bytes() - n.offset.bytes())
+ }),
+ };
+
+ (
+ // Place ZSTs first to avoid "interesting offsets", especially with only one
+ // or two non-ZST fields. This helps Scalar/ScalarPair layouts.
+ !f.0.is_zst(),
+ // Then place largest alignments first.
+ cmp::Reverse(alignment_group_key(f)),
+ // Then prioritize niche placement within alignment group according to
+ // `niche_bias_start`.
+ niche_size_key,
+ // Then among fields with equally-sized niches prefer the ones
+ // closer to the start/end of the field.
+ inner_niche_offset_key,
+ )
+ });
+ }
+
+ StructKind::Prefixed(..) => {
+ // Sort in ascending alignment so that the layout stays optimal
+ // regardless of the prefix.
+ // And put the largest niche in an alignment group at the end
+ // so it can be used as discriminant in jagged enums
+ optimizing.sort_by_key(|&x| {
+ let f = fields[x];
+ let niche_size = f.largest_niche().map_or(0, |n| n.available(dl));
+ (alignment_group_key(f), niche_size)
+ });
+ }
+ }
+
+ // FIXME(Kixiron): We can always shuffle fields within a given alignment class
+ // regardless of the status of `-Z randomize-layout`
+ }
+ }
+ // inverse_memory_index holds field indices by increasing memory offset.
+ // That is, if field 5 has offset 0, the first element of inverse_memory_index is 5.
+ // We now write field offsets to the corresponding offset slot;
+ // field 5 with offset 0 puts 0 in offsets[5].
+ // At the bottom of this function, we invert `inverse_memory_index` to
+ // produce `memory_index` (see `invert_mapping`).
+ let mut sized = true;
+ let mut offsets = IndexVec::from_elem(Size::ZERO, &fields);
+ let mut offset = Size::ZERO;
+ let mut largest_niche = None;
+ let mut largest_niche_available = 0;
+ if let StructKind::Prefixed(prefix_size, prefix_align) = kind {
+ let prefix_align =
+ if let Some(pack) = pack { prefix_align.min(pack) } else { prefix_align };
+ align = align.max(AbiAndPrefAlign::new(prefix_align));
+ offset = prefix_size.align_to(prefix_align);
+ }
+ for &i in &inverse_memory_index {
+ let field = &fields[i];
+ if !sized {
+ this.delay_bug(format!(
+ "univariant: field #{} comes after unsized field",
+ offsets.len(),
+ ));
+ }
+
+ if field.0.is_unsized() {
+ sized = false;
+ }
+
+ // Invariant: offset < dl.obj_size_bound() <= 1<<61
+ let field_align = if let Some(pack) = pack {
+ field.align().min(AbiAndPrefAlign::new(pack))
+ } else {
+ field.align()
+ };
+ offset = offset.align_to(field_align.abi);
+ align = align.max(field_align);
+
+ debug!("univariant offset: {:?} field: {:#?}", offset, field);
+ offsets[i] = offset;
+
+ if let Some(mut niche) = field.largest_niche() {
+ let available = niche.available(dl);
+ // Pick up larger niches.
+ let prefer_new_niche = match niche_bias {
+ NicheBias::Start => available > largest_niche_available,
+ // if there are several niches of the same size then pick the last one
+ NicheBias::End => available >= largest_niche_available,
+ };
+ if prefer_new_niche {
+ largest_niche_available = available;
+ niche.offset += offset;
+ largest_niche = Some(niche);
+ }
+ }
+
+ offset = offset.checked_add(field.size(), dl)?;
+ }
+ if let Some(repr_align) = repr.align {
+ align = align.max(AbiAndPrefAlign::new(repr_align));
+ }
+ debug!("univariant min_size: {:?}", offset);
+ let min_size = offset;
+ // As stated above, inverse_memory_index holds field indices by increasing offset.
+ // This makes it an already-sorted view of the offsets vec.
+ // To invert it, consider:
+ // If field 5 has offset 0, offsets[0] is 5, and memory_index[5] should be 0.
+ // Field 5 would be the first element, so memory_index is i:
+ // Note: if we didn't optimize, it's already right.
+ let memory_index = if optimize {
+ inverse_memory_index.invert_bijective_mapping()
+ } else {
+ debug_assert!(inverse_memory_index.iter().copied().eq(fields.indices()));
+ inverse_memory_index.into_iter().map(FieldIdx::as_u32).collect()
+ };
+ let size = min_size.align_to(align.abi);
+ let mut abi = Abi::Aggregate { sized };
+ // Unpack newtype ABIs and find scalar pairs.
+ if sized && size.bytes() > 0 {
+ // All other fields must be ZSTs.
+ let mut non_zst_fields = fields.iter_enumerated().filter(|&(_, f)| !f.0.is_zst());
+
+ match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) {
+ // We have exactly one non-ZST field.
+ (Some((i, field)), None, None) => {
+ // Field fills the struct and it has a scalar or scalar pair ABI.
+ if offsets[i].bytes() == 0 && align.abi == field.align().abi && size == field.size()
+ {
+ match field.abi() {
+ // For plain scalars, or vectors of them, we can't unpack
+ // newtypes for `#[repr(C)]`, as that affects C ABIs.
+ Abi::Scalar(_) | Abi::Vector { .. } if optimize => {
+ abi = field.abi();
+ }
+ // But scalar pairs are Rust-specific and get
+ // treated as aggregates by C ABIs anyway.
+ Abi::ScalarPair(..) => {
+ abi = field.abi();
+ }
+ _ => {}
+ }
+ }
+ }
+
+ // Two non-ZST fields, and they're both scalars.
+ (Some((i, a)), Some((j, b)), None) => {
+ match (a.abi(), b.abi()) {
+ (Abi::Scalar(a), Abi::Scalar(b)) => {
+ // Order by the memory placement, not source order.
+ let ((i, a), (j, b)) = if offsets[i] < offsets[j] {
+ ((i, a), (j, b))
+ } else {
+ ((j, b), (i, a))
+ };
+ let pair = this.scalar_pair(a, b);
+ let pair_offsets = match pair.fields {
+ FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+ assert_eq!(memory_index.raw, [0, 1]);
+ offsets
+ }
+ _ => panic!(),
+ };
+ if offsets[i] == pair_offsets[FieldIdx::from_usize(0)]
+ && offsets[j] == pair_offsets[FieldIdx::from_usize(1)]
+ && align == pair.align
+ && size == pair.size
+ {
+ // We can use `ScalarPair` only when it matches our
+ // already computed layout (including `#[repr(C)]`).
+ abi = pair.abi;
+ }
+ }
+ _ => {}
+ }
+ }
+
+ _ => {}
+ }
+ }
+ if fields.iter().any(|f| f.abi().is_uninhabited()) {
+ abi = Abi::Uninhabited;
+ }
+ Some(LayoutS {
+ variants: Variants::Single { index: FIRST_VARIANT },
+ fields: FieldsShape::Arbitrary { offsets, memory_index },
+ abi,
+ largest_niche,
+ align,
+ size,
+ })
+}
+
+fn format_field_niches(
+ layout: &LayoutS,
+ fields: &IndexSlice<FieldIdx, Layout<'_>>,
+ dl: &TargetDataLayout,
+) -> String {
+ let mut s = String::new();
+ for i in layout.fields.index_by_increasing_offset() {
+ let offset = layout.fields.offset(i);
+ let f = fields[i.into()];
+ write!(s, "[o{}a{}s{}", offset.bytes(), f.align().abi.bytes(), f.size().bytes()).unwrap();
+ if let Some(n) = f.largest_niche() {
+ write!(
+ s,
+ " n{}b{}s{}",
+ n.offset.bytes(),
+ n.available(dl).ilog2(),
+ n.value.size(dl).bytes()
+ )
+ .unwrap();
+ }
+ write!(s, "] ").unwrap();
+ }
+ s
+}
diff --git a/compiler/rustc_abi/src/lib.rs b/compiler/rustc_abi/src/lib.rs
index b0c0ee942..43db66a3c 100644
--- a/compiler/rustc_abi/src/lib.rs
+++ b/compiler/rustc_abi/src/lib.rs
@@ -9,9 +9,10 @@ use std::str::FromStr;
use bitflags::bitflags;
use rustc_data_structures::intern::Interned;
+use rustc_data_structures::stable_hasher::Hash64;
#[cfg(feature = "nightly")]
use rustc_data_structures::stable_hasher::StableOrd;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
#[cfg(feature = "nightly")]
use rustc_macros::HashStable_Generic;
#[cfg(feature = "nightly")]
@@ -77,12 +78,12 @@ pub struct ReprOptions {
pub flags: ReprFlags,
/// The seed to be used for randomizing a type's layout
///
- /// Note: This could technically be a `[u8; 16]` (a `u128`) which would
+ /// Note: This could technically be a `Hash128` which would
/// be the "most accurate" hash as it'd encompass the item and crate
/// hash without loss, but it does pay the price of being larger.
- /// Everything's a tradeoff, a `u64` seed should be sufficient for our
+ /// Everything's a tradeoff, a 64-bit seed should be sufficient for our
/// purposes (primarily `-Z randomize-layout`)
- pub field_shuffle_seed: u64,
+ pub field_shuffle_seed: Hash64,
}
impl ReprOptions {
@@ -665,15 +666,12 @@ impl Align {
format!("`{}` is too large", align)
}
- let mut bytes = align;
- let mut pow2: u8 = 0;
- while (bytes & 1) == 0 {
- pow2 += 1;
- bytes >>= 1;
- }
- if bytes != 1 {
+ let tz = align.trailing_zeros();
+ if align != (1 << tz) {
return Err(not_power_of_2(align));
}
+
+ let pow2 = tz as u8;
if pow2 > Self::MAX.pow2 {
return Err(too_large(align));
}
@@ -1274,6 +1272,50 @@ impl Abi {
pub fn is_scalar(&self) -> bool {
matches!(*self, Abi::Scalar(_))
}
+
+ /// Returns the fixed alignment of this ABI, if any is mandated.
+ pub fn inherent_align<C: HasDataLayout>(&self, cx: &C) -> Option<AbiAndPrefAlign> {
+ Some(match *self {
+ Abi::Scalar(s) => s.align(cx),
+ Abi::ScalarPair(s1, s2) => s1.align(cx).max(s2.align(cx)),
+ Abi::Vector { element, count } => {
+ cx.data_layout().vector_align(element.size(cx) * count)
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+ })
+ }
+
+ /// Returns the fixed size of this ABI, if any is mandated.
+ pub fn inherent_size<C: HasDataLayout>(&self, cx: &C) -> Option<Size> {
+ Some(match *self {
+ Abi::Scalar(s) => {
+ // No padding in scalars.
+ s.size(cx)
+ }
+ Abi::ScalarPair(s1, s2) => {
+ // May have some padding between the pair.
+ let field2_offset = s1.size(cx).align_to(s2.align(cx).abi);
+ (field2_offset + s2.size(cx)).align_to(self.inherent_align(cx)?.abi)
+ }
+ Abi::Vector { element, count } => {
+ // No padding in vectors, except possibly for trailing padding
+ // to make the size a multiple of align (e.g. for vectors of size 3).
+ (element.size(cx) * count).align_to(self.inherent_align(cx)?.abi)
+ }
+ Abi::Uninhabited | Abi::Aggregate { .. } => return None,
+ })
+ }
+
+ /// Discard validity range information and allow undef.
+ pub fn to_union(&self) -> Self {
+ assert!(self.is_sized());
+ match *self {
+ Abi::Scalar(s) => Abi::Scalar(s.to_union()),
+ Abi::ScalarPair(s1, s2) => Abi::ScalarPair(s1.to_union(), s2.to_union()),
+ Abi::Vector { element, count } => Abi::Vector { element: element.to_union(), count },
+ Abi::Uninhabited | Abi::Aggregate { .. } => Abi::Aggregate { sized: true },
+ }
+ }
}
#[derive(PartialEq, Eq, Hash, Clone, Debug)]
diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs
index 345e058e1..6e15f06a7 100644
--- a/compiler/rustc_arena/src/lib.rs
+++ b/compiler/rustc_arena/src/lib.rs
@@ -20,6 +20,7 @@
#![feature(rustc_attrs)]
#![cfg_attr(test, feature(test))]
#![feature(strict_provenance)]
+#![deny(unsafe_op_in_unsafe_fn)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#![allow(clippy::mut_from_ref)] // Arena allocators are one of the places where this pattern is fine.
@@ -74,19 +75,27 @@ impl<T> ArenaChunk<T> {
#[inline]
unsafe fn new(capacity: usize) -> ArenaChunk<T> {
ArenaChunk {
- storage: NonNull::new(Box::into_raw(Box::new_uninit_slice(capacity))).unwrap(),
+ storage: NonNull::from(Box::leak(Box::new_uninit_slice(capacity))),
entries: 0,
}
}
/// Destroys this arena chunk.
+ ///
+ /// # Safety
+ ///
+ /// The caller must ensure that `len` elements of this chunk have been initialized.
#[inline]
unsafe fn destroy(&mut self, len: usize) {
// The branch on needs_drop() is an -O1 performance optimization.
- // Without the branch, dropping TypedArena<u8> takes linear time.
+ // Without the branch, dropping TypedArena<T> takes linear time.
if mem::needs_drop::<T>() {
- let slice = &mut *(self.storage.as_mut());
- ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
+ // SAFETY: The caller must ensure that `len` elements of this chunk have
+ // been initialized.
+ unsafe {
+ let slice = self.storage.as_mut();
+ ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut slice[..len]));
+ }
}
}
@@ -104,7 +113,7 @@ impl<T> ArenaChunk<T> {
// A pointer as large as possible for zero-sized elements.
ptr::invalid_mut(!0)
} else {
- self.start().add((*self.storage.as_ptr()).len())
+ self.start().add(self.storage.len())
}
}
}
@@ -255,7 +264,9 @@ impl<T> TypedArena<T> {
self.ensure_capacity(len);
let start_ptr = self.ptr.get();
- self.ptr.set(start_ptr.add(len));
+ // SAFETY: `self.ensure_capacity` makes sure that there is enough space
+ // for `len` elements.
+ unsafe { self.ptr.set(start_ptr.add(len)) };
start_ptr
}
@@ -288,7 +299,7 @@ impl<T> TypedArena<T> {
// If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
- new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / elem_size / 2);
+ new_cap = last_chunk.storage.len().min(HUGE_PAGE / elem_size / 2);
new_cap *= 2;
} else {
new_cap = PAGE / elem_size;
@@ -396,7 +407,7 @@ impl DroplessArena {
// If the previous chunk's len is less than HUGE_PAGE
// bytes, then this chunk will be least double the previous
// chunk's size.
- new_cap = (*last_chunk.storage.as_ptr()).len().min(HUGE_PAGE / 2);
+ new_cap = last_chunk.storage.len().min(HUGE_PAGE / 2);
new_cap *= 2;
} else {
new_cap = PAGE;
@@ -483,6 +494,10 @@ impl DroplessArena {
}
}
+ /// # Safety
+ ///
+ /// The caller must ensure that `mem` is valid for writes up to
+ /// `size_of::<T>() * len`.
#[inline]
unsafe fn write_from_iter<T, I: Iterator<Item = T>>(
&self,
@@ -494,13 +509,18 @@ impl DroplessArena {
// Use a manual loop since LLVM manages to optimize it better for
// slice iterators
loop {
- let value = iter.next();
- if i >= len || value.is_none() {
- // We only return as many items as the iterator gave us, even
- // though it was supposed to give us `len`
- return slice::from_raw_parts_mut(mem, i);
+ // SAFETY: The caller must ensure that `mem` is valid for writes up to
+ // `size_of::<T>() * len`.
+ unsafe {
+ match iter.next() {
+ Some(value) if i < len => mem.add(i).write(value),
+ Some(_) | None => {
+ // We only return as many items as the iterator gave us, even
+ // though it was supposed to give us `len`
+ return slice::from_raw_parts_mut(mem, i);
+ }
+ }
}
- ptr::write(mem.add(i), value.unwrap());
i += 1;
}
}
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index df1a71675..4360fbeb9 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -120,6 +120,12 @@ impl Path {
pub fn is_global(&self) -> bool {
!self.segments.is_empty() && self.segments[0].ident.name == kw::PathRoot
}
+
+ /// If this path is a single identifier with no arguments, does not ensure
+ /// that the path resolves to a const param, the caller should check this.
+ pub fn is_potential_trivial_const_arg(&self) -> bool {
+ self.segments.len() == 1 && self.segments[0].args.is_none()
+ }
}
/// A segment of a path: an identifier, an optional lifetime, and a set of types.
@@ -287,12 +293,20 @@ pub enum TraitBoundModifier {
/// No modifiers
None,
+ /// `!Trait`
+ Negative,
+
/// `?Trait`
Maybe,
/// `~const Trait`
MaybeConst,
+ /// `~const !Trait`
+ //
+ // This parses but will be rejected during AST validation.
+ MaybeConstNegative,
+
/// `~const ?Trait`
//
// This parses but will be rejected during AST validation.
@@ -1146,7 +1160,9 @@ impl Expr {
///
/// If this is not the case, name resolution does not resolve `N` when using
/// `min_const_generics` as more complex expressions are not supported.
- pub fn is_potential_trivial_const_param(&self) -> bool {
+ ///
+ /// Does not ensure that the path resolves to a const param, the caller should check this.
+ pub fn is_potential_trivial_const_arg(&self) -> bool {
let this = if let ExprKind::Block(block, None) = &self.kind
&& block.stmts.len() == 1
&& let StmtKind::Expr(expr) = &block.stmts[0].kind
@@ -1157,8 +1173,7 @@ impl Expr {
};
if let ExprKind::Path(None, path) = &this.kind
- && path.segments.len() == 1
- && path.segments[0].args.is_none()
+ && path.is_potential_trivial_const_arg()
{
true
} else {
@@ -1271,6 +1286,7 @@ impl Expr {
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
+ ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf,
ExprKind::MacCall(..) => ExprPrecedence::Mac,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
@@ -1298,17 +1314,17 @@ impl Expr {
/// To a first-order approximation, is this a pattern?
pub fn is_approximately_pattern(&self) -> bool {
- match &self.peel_parens().kind {
+ matches!(
+ &self.peel_parens().kind,
ExprKind::Array(_)
- | ExprKind::Call(_, _)
- | ExprKind::Tup(_)
- | ExprKind::Lit(_)
- | ExprKind::Range(_, _, _)
- | ExprKind::Underscore
- | ExprKind::Path(_, _)
- | ExprKind::Struct(_) => true,
- _ => false,
- }
+ | ExprKind::Call(_, _)
+ | ExprKind::Tup(_)
+ | ExprKind::Lit(_)
+ | ExprKind::Range(_, _, _)
+ | ExprKind::Underscore
+ | ExprKind::Path(_, _)
+ | ExprKind::Struct(_)
+ )
}
}
@@ -1429,8 +1445,8 @@ pub enum ExprKind {
/// The async block used to have a `NodeId`, which was removed in favor of
/// using the parent `NodeId` of the parent `Expr`.
Async(CaptureBy, P<Block>),
- /// An await expression (`my_future.await`).
- Await(P<Expr>),
+ /// An await expression (`my_future.await`). Span is of await keyword.
+ Await(P<Expr>, Span),
/// A try block (`try { ... }`).
TryBlock(P<Block>),
@@ -1469,6 +1485,9 @@ pub enum ExprKind {
/// Output of the `asm!()` macro.
InlineAsm(P<InlineAsm>),
+ /// Output of the `offset_of!()` macro.
+ OffsetOf(P<Ty>, P<[Ident]>),
+
/// A macro invocation; pre-expansion.
MacCall(P<MacCall>),
@@ -1585,7 +1604,6 @@ pub enum ClosureBinder {
pub struct MacCall {
pub path: Path,
pub args: P<DelimArgs>,
- pub prior_type_ascription: Option<(Span, bool)>,
}
impl MacCall {
@@ -1810,6 +1828,8 @@ pub enum LitKind {
/// A byte string (`b"foo"`). Not stored as a symbol because it might be
/// non-utf8, and symbols only allow utf8 strings.
ByteStr(Lrc<[u8]>, StrStyle),
+ /// A C String (`c"foo"`). Guaranteed to only have `\0` at the end.
+ CStr(Lrc<[u8]>, StrStyle),
/// A byte char (`b'f'`).
Byte(u8),
/// A character literal (`'a'`).
@@ -1864,6 +1884,7 @@ impl LitKind {
// unsuffixed variants
LitKind::Str(..)
| LitKind::ByteStr(..)
+ | LitKind::CStr(..)
| LitKind::Byte(..)
| LitKind::Char(..)
| LitKind::Int(_, LitIntType::Unsuffixed)
@@ -2370,10 +2391,10 @@ pub struct FnDecl {
impl FnDecl {
pub fn has_self(&self) -> bool {
- self.inputs.get(0).map_or(false, Param::is_self)
+ self.inputs.get(0).is_some_and(Param::is_self)
}
pub fn c_variadic(&self) -> bool {
- self.inputs.last().map_or(false, |arg| matches!(arg.ty.kind, TyKind::CVarArgs))
+ self.inputs.last().is_some_and(|arg| matches!(arg.ty.kind, TyKind::CVarArgs))
}
}
@@ -2443,6 +2464,16 @@ impl fmt::Debug for ImplPolarity {
}
}
+#[derive(Copy, Clone, PartialEq, Encodable, Decodable, HashStable_Generic)]
+pub enum BoundPolarity {
+ /// `Type: Trait`
+ Positive,
+ /// `Type: !Trait`
+ Negative(Span),
+ /// `Type: ?Trait`
+ Maybe(Span),
+}
+
#[derive(Clone, Encodable, Decodable, Debug)]
pub enum FnRetTy {
/// Returns type is not specified.
@@ -2972,7 +3003,7 @@ pub enum ItemKind {
}
impl ItemKind {
- pub fn article(&self) -> &str {
+ pub fn article(&self) -> &'static str {
use ItemKind::*;
match self {
Use(..) | Static(..) | Const(..) | Fn(..) | Mod(..) | GlobalAsm(..) | TyAlias(..)
@@ -2981,7 +3012,7 @@ impl ItemKind {
}
}
- pub fn descr(&self) -> &str {
+ pub fn descr(&self) -> &'static str {
match self {
ItemKind::ExternCrate(..) => "extern crate",
ItemKind::Use(..) => "`use` import",
diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs
index c4771115c..15fe29580 100644
--- a/compiler/rustc_ast/src/attr/mod.rs
+++ b/compiler/rustc_ast/src/attr/mod.rs
@@ -10,15 +10,10 @@ use crate::tokenstream::{DelimSpan, Spacing, TokenTree};
use crate::tokenstream::{LazyAttrTokenStream, TokenStream};
use crate::util::comments;
use crate::util::literal::escape_string_symbol;
-use rustc_data_structures::sync::WorkerLocal;
use rustc_index::bit_set::GrowableBitSet;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::Span;
-use std::cell::Cell;
use std::iter;
-#[cfg(debug_assertions)]
-use std::ops::BitXor;
-#[cfg(debug_assertions)]
use std::sync::atomic::{AtomicU32, Ordering};
use thin_vec::{thin_vec, ThinVec};
@@ -40,39 +35,16 @@ impl MarkedAttrs {
}
}
-pub struct AttrIdGenerator(WorkerLocal<Cell<u32>>);
-
-#[cfg(debug_assertions)]
-static MAX_ATTR_ID: AtomicU32 = AtomicU32::new(u32::MAX);
+pub struct AttrIdGenerator(AtomicU32);
impl AttrIdGenerator {
pub fn new() -> Self {
- // We use `(index as u32).reverse_bits()` to initialize the
- // starting value of AttrId in each worker thread.
- // The `index` is the index of the worker thread.
- // This ensures that the AttrId generated in each thread is unique.
- AttrIdGenerator(WorkerLocal::new(|index| {
- let index: u32 = index.try_into().unwrap();
-
- #[cfg(debug_assertions)]
- {
- let max_id = ((index + 1).next_power_of_two() - 1).bitxor(u32::MAX).reverse_bits();
- MAX_ATTR_ID.fetch_min(max_id, Ordering::Release);
- }
-
- Cell::new(index.reverse_bits())
- }))
+ AttrIdGenerator(AtomicU32::new(0))
}
pub fn mk_attr_id(&self) -> AttrId {
- let id = self.0.get();
-
- // Ensure the assigned attr_id does not overlap the bits
- // representing the number of threads.
- #[cfg(debug_assertions)]
- assert!(id <= MAX_ATTR_ID.load(Ordering::Acquire));
-
- self.0.set(id + 1);
+ let id = self.0.fetch_add(1, Ordering::Relaxed);
+ assert!(id != u32::MAX);
AttrId::from_u32(id)
}
}
@@ -177,7 +149,7 @@ impl Attribute {
}
pub fn may_have_doc_links(&self) -> bool {
- self.doc_str().map_or(false, |s| comments::may_have_doc_links(s.as_str()))
+ self.doc_str().is_some_and(|s| comments::may_have_doc_links(s.as_str()))
}
pub fn is_proc_macro_attr(&self) -> bool {
@@ -469,12 +441,12 @@ impl NestedMetaItem {
/// Returns `true` if this list item is a MetaItem with a name of `name`.
pub fn has_name(&self, name: Symbol) -> bool {
- self.meta_item().map_or(false, |meta_item| meta_item.has_name(name))
+ self.meta_item().is_some_and(|meta_item| meta_item.has_name(name))
}
/// Returns `true` if `self` is a `MetaItem` and the meta item is a word.
pub fn is_word(&self) -> bool {
- self.meta_item().map_or(false, |meta_item| meta_item.is_word())
+ self.meta_item().is_some_and(|meta_item| meta_item.is_word())
}
/// Gets a list of inner meta items from a list `MetaItem` type.
diff --git a/compiler/rustc_ast/src/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs
index 359394963..e87f6e820 100644
--- a/compiler/rustc_ast/src/expand/allocator.rs
+++ b/compiler/rustc_ast/src/expand/allocator.rs
@@ -1,20 +1,28 @@
use rustc_span::symbol::{sym, Symbol};
-#[derive(Clone, Debug, Copy, HashStable_Generic)]
+#[derive(Clone, Debug, Copy, Eq, PartialEq, HashStable_Generic)]
pub enum AllocatorKind {
Global,
Default,
}
-impl AllocatorKind {
- pub fn fn_name(&self, base: Symbol) -> String {
- match *self {
- AllocatorKind::Global => format!("__rg_{base}"),
- AllocatorKind::Default => format!("__rdl_{base}"),
- }
+pub fn global_fn_name(base: Symbol) -> String {
+ format!("__rust_{base}")
+}
+
+pub fn default_fn_name(base: Symbol) -> String {
+ format!("__rdl_{base}")
+}
+
+pub fn alloc_error_handler_name(alloc_error_handler_kind: AllocatorKind) -> &'static str {
+ match alloc_error_handler_kind {
+ AllocatorKind::Global => "__rg_oom",
+ AllocatorKind::Default => "__rdl_oom",
}
}
+pub const NO_ALLOC_SHIM_IS_UNSTABLE: &str = "__rust_no_alloc_shim_is_unstable";
+
pub enum AllocatorTy {
Layout,
Ptr,
diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs
index 23c32fa96..b07ed1d1c 100644
--- a/compiler/rustc_ast/src/lib.rs
+++ b/compiler/rustc_ast/src/lib.rs
@@ -10,7 +10,6 @@
)]
#![feature(associated_type_bounds)]
#![feature(box_patterns)]
-#![feature(const_default_impls)]
#![feature(const_trait_impl)]
#![feature(if_let_guard)]
#![feature(let_chains)]
diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs
index 694d31d8f..66b94d12a 100644
--- a/compiler/rustc_ast/src/mut_visit.rs
+++ b/compiler/rustc_ast/src/mut_visit.rs
@@ -631,7 +631,7 @@ pub fn noop_visit_attribute<T: MutVisitor>(attr: &mut Attribute, vis: &mut T) {
}
pub fn noop_visit_mac<T: MutVisitor>(mac: &mut MacCall, vis: &mut T) {
- let MacCall { path, args, prior_type_ascription: _ } = mac;
+ let MacCall { path, args } = mac;
vis.visit_path(path);
visit_delim_args(args, vis);
}
@@ -1415,7 +1415,10 @@ pub fn noop_visit_expr<T: MutVisitor>(
ExprKind::Async(_capture_by, body) => {
vis.visit_block(body);
}
- ExprKind::Await(expr) => vis.visit_expr(expr),
+ ExprKind::Await(expr, await_kw_span) => {
+ vis.visit_expr(expr);
+ vis.visit_span(await_kw_span);
+ }
ExprKind::Assign(el, er, _) => {
vis.visit_expr(el);
vis.visit_expr(er);
@@ -1456,6 +1459,12 @@ pub fn noop_visit_expr<T: MutVisitor>(
}
ExprKind::InlineAsm(asm) => vis.visit_inline_asm(asm),
ExprKind::FormatArgs(fmt) => vis.visit_format_args(fmt),
+ ExprKind::OffsetOf(container, fields) => {
+ vis.visit_ty(container);
+ for field in fields.iter_mut() {
+ vis.visit_ident(field);
+ }
+ }
ExprKind::MacCall(mac) => vis.visit_mac_call(mac),
ExprKind::Struct(se) => {
let StructExpr { qself, path, fields, rest } = se.deref_mut();
diff --git a/compiler/rustc_ast/src/node_id.rs b/compiler/rustc_ast/src/node_id.rs
index daa82996b..d16741757 100644
--- a/compiler/rustc_ast/src/node_id.rs
+++ b/compiler/rustc_ast/src/node_id.rs
@@ -9,14 +9,14 @@ rustc_index::newtype_index! {
///
/// [`DefId`]: rustc_span::def_id::DefId
#[debug_format = "NodeId({})"]
- pub struct NodeId {}
+ pub struct NodeId {
+ /// The [`NodeId`] used to represent the root of the crate.
+ const CRATE_NODE_ID = 0;
+ }
}
rustc_data_structures::define_id_collections!(NodeMap, NodeSet, NodeMapEntry, NodeId);
-/// The [`NodeId`] used to represent the root of the crate.
-pub const CRATE_NODE_ID: NodeId = NodeId::from_u32(0);
-
/// When parsing and at the beginning of doing expansions, we initially give all AST nodes
/// this dummy AST [`NodeId`]. Then, during a later phase of expansion, we renumber them
/// to have small, positive IDs.
diff --git a/compiler/rustc_ast/src/ptr.rs b/compiler/rustc_ast/src/ptr.rs
index 4b2850336..0140fb752 100644
--- a/compiler/rustc_ast/src/ptr.rs
+++ b/compiler/rustc_ast/src/ptr.rs
@@ -126,7 +126,8 @@ impl<S: Encoder, T: Encodable<S>> Encodable<S> for P<T> {
}
impl<T> P<[T]> {
- pub const fn new() -> P<[T]> {
+ // FIXME(const-hack) make this const again
+ pub fn new() -> P<[T]> {
P { ptr: Box::default() }
}
diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs
index f947ae4d0..7ef39f802 100644
--- a/compiler/rustc_ast/src/token.rs
+++ b/compiler/rustc_ast/src/token.rs
@@ -74,6 +74,8 @@ pub enum LitKind {
StrRaw(u8), // raw string delimited by `n` hash symbols
ByteStr,
ByteStrRaw(u8), // raw byte string delimited by `n` hash symbols
+ CStr,
+ CStrRaw(u8),
Err,
}
@@ -141,6 +143,10 @@ impl fmt::Display for Lit {
delim = "#".repeat(n as usize),
string = symbol
)?,
+ CStr => write!(f, "c\"{symbol}\"")?,
+ CStrRaw(n) => {
+ write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))?
+ }
Integer | Float | Bool | Err => write!(f, "{symbol}")?,
}
@@ -170,6 +176,7 @@ impl LitKind {
Float => "float",
Str | StrRaw(..) => "string",
ByteStr | ByteStrRaw(..) => "byte string",
+ CStr | CStrRaw(..) => "C string",
Err => "error",
}
}
@@ -600,7 +607,7 @@ impl Token {
/// Returns `true` if the token is an identifier whose name is the given
/// string slice.
pub fn is_ident_named(&self, name: Symbol) -> bool {
- self.ident().map_or(false, |(ident, _)| ident.name == name)
+ self.ident().is_some_and(|(ident, _)| ident.name == name)
}
/// Returns `true` if the token is an interpolated path.
diff --git a/compiler/rustc_ast/src/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs
index f0a6a5e07..db296aa44 100644
--- a/compiler/rustc_ast/src/tokenstream.rs
+++ b/compiler/rustc_ast/src/tokenstream.rs
@@ -48,14 +48,15 @@ pub enum TokenTree {
Delimited(DelimSpan, Delimiter, TokenStream),
}
-// Ensure all fields of `TokenTree` is `Send` and `Sync`.
+// Ensure all fields of `TokenTree` are `DynSend` and `DynSync`.
#[cfg(parallel_compiler)]
fn _dummy()
where
- Token: Send + Sync,
- DelimSpan: Send + Sync,
- Delimiter: Send + Sync,
- TokenStream: Send + Sync,
+ Token: sync::DynSend + sync::DynSync,
+ Spacing: sync::DynSend + sync::DynSync,
+ DelimSpan: sync::DynSend + sync::DynSync,
+ Delimiter: sync::DynSend + sync::DynSync,
+ TokenStream: sync::DynSend + sync::DynSync,
{
}
@@ -118,7 +119,7 @@ where
}
}
-pub trait ToAttrTokenStream: sync::Send + sync::Sync {
+pub trait ToAttrTokenStream: sync::DynSend + sync::DynSync {
fn to_attr_token_stream(&self) -> AttrTokenStream;
}
@@ -550,6 +551,10 @@ impl TokenStream {
vec_mut.extend(stream_iter);
}
}
+
+ pub fn chunks(&self, chunk_size: usize) -> core::slice::Chunks<'_, TokenTree> {
+ self.0.chunks(chunk_size)
+ }
}
/// By-reference iterator over a [`TokenStream`], that produces `&TokenTree`
diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs
index 74b842ac9..50eb92125 100644
--- a/compiler/rustc_ast/src/util/literal.rs
+++ b/compiler/rustc_ast/src/util/literal.rs
@@ -2,9 +2,13 @@
use crate::ast::{self, LitKind, MetaItemLit, StrStyle};
use crate::token::{self, Token};
-use rustc_lexer::unescape::{byte_from_char, unescape_byte, unescape_char, unescape_literal, Mode};
+use rustc_lexer::unescape::{
+ byte_from_char, unescape_byte, unescape_c_string, unescape_char, unescape_literal, CStrUnit,
+ Mode,
+};
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
+use std::ops::Range;
use std::{ascii, fmt, str};
// Escapes a string, represented as a symbol. Reuses the original symbol,
@@ -35,6 +39,7 @@ pub enum LitError {
InvalidFloatSuffix,
NonDecimalFloat(u32),
IntTooLarge(u32),
+ NulInCStr(Range<usize>),
}
impl LitKind {
@@ -158,6 +163,52 @@ impl LitKind {
LitKind::ByteStr(bytes.into(), StrStyle::Raw(n))
}
+ token::CStr => {
+ let s = symbol.as_str();
+ let mut buf = Vec::with_capacity(s.len());
+ let mut error = Ok(());
+ unescape_c_string(s, Mode::CStr, &mut |span, c| match c {
+ Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+ error = Err(LitError::NulInCStr(span));
+ }
+ Ok(CStrUnit::Byte(b)) => buf.push(b),
+ Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+ Ok(CStrUnit::Char(c)) => {
+ buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+ }
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
+ });
+ error?;
+ buf.push(0);
+ LitKind::CStr(buf.into(), StrStyle::Cooked)
+ }
+ token::CStrRaw(n) => {
+ let s = symbol.as_str();
+ let mut buf = Vec::with_capacity(s.len());
+ let mut error = Ok(());
+ unescape_c_string(s, Mode::RawCStr, &mut |span, c| match c {
+ Ok(CStrUnit::Byte(0) | CStrUnit::Char('\0')) => {
+ error = Err(LitError::NulInCStr(span));
+ }
+ Ok(CStrUnit::Byte(b)) => buf.push(b),
+ Ok(CStrUnit::Char(c)) if c.len_utf8() == 1 => buf.push(c as u8),
+ Ok(CStrUnit::Char(c)) => {
+ buf.extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes())
+ }
+ Err(err) => {
+ if err.is_fatal() {
+ error = Err(LitError::LexerError);
+ }
+ }
+ });
+ error?;
+ buf.push(0);
+ LitKind::CStr(buf.into(), StrStyle::Raw(n))
+ }
token::Err => LitKind::Err,
})
}
@@ -191,6 +242,14 @@ impl fmt::Display for LitKind {
string = symbol
)?;
}
+ LitKind::CStr(ref bytes, StrStyle::Cooked) => {
+ write!(f, "c\"{}\"", escape_byte_str_symbol(bytes))?
+ }
+ LitKind::CStr(ref bytes, StrStyle::Raw(n)) => {
+ // This can only be valid UTF-8.
+ let symbol = str::from_utf8(bytes).unwrap();
+ write!(f, "cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize),)?;
+ }
LitKind::Int(n, ty) => {
write!(f, "{n}")?;
match ty {
@@ -237,6 +296,8 @@ impl MetaItemLit {
LitKind::Str(_, ast::StrStyle::Raw(n)) => token::StrRaw(n),
LitKind::ByteStr(_, ast::StrStyle::Cooked) => token::ByteStr,
LitKind::ByteStr(_, ast::StrStyle::Raw(n)) => token::ByteStrRaw(n),
+ LitKind::CStr(_, ast::StrStyle::Cooked) => token::CStr,
+ LitKind::CStr(_, ast::StrStyle::Raw(n)) => token::CStrRaw(n),
LitKind::Byte(_) => token::Byte,
LitKind::Char(_) => token::Char,
LitKind::Int(..) => token::Integer,
@@ -331,8 +392,7 @@ fn integer_lit(symbol: Symbol, suffix: Option<Symbol>) -> Result<LitKind, LitErr
// Small bases are lexed as if they were base 10, e.g, the string
// might be `0b10201`. This will cause the conversion above to fail,
// but these kinds of errors are already reported by the lexer.
- let from_lexer =
- base < 10 && s.chars().any(|c| c.to_digit(10).map_or(false, |d| d >= base));
+ let from_lexer = base < 10 && s.chars().any(|c| c.to_digit(10).is_some_and(|d| d >= base));
if from_lexer { LitError::LexerError } else { LitError::IntTooLarge(base) }
})
}
diff --git a/compiler/rustc_ast/src/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs
index 3893875e9..35afd5423 100644
--- a/compiler/rustc_ast/src/util/parser.rs
+++ b/compiler/rustc_ast/src/util/parser.rs
@@ -53,8 +53,6 @@ pub enum AssocOp {
DotDot,
/// `..=` range
DotDotEq,
- /// `:`
- Colon,
}
#[derive(PartialEq, Debug)]
@@ -96,7 +94,6 @@ impl AssocOp {
token::DotDotEq => Some(DotDotEq),
// DotDotDot is no longer supported, but we need some way to display the error
token::DotDotDot => Some(DotDotEq),
- token::Colon => Some(Colon),
// `<-` should probably be `< -`
token::LArrow => Some(Less),
_ if t.is_keyword(kw::As) => Some(As),
@@ -133,7 +130,7 @@ impl AssocOp {
pub fn precedence(&self) -> usize {
use AssocOp::*;
match *self {
- As | Colon => 14,
+ As => 14,
Multiply | Divide | Modulus => 13,
Add | Subtract => 12,
ShiftLeft | ShiftRight => 11,
@@ -156,7 +153,7 @@ impl AssocOp {
Assign | AssignOp(_) => Fixity::Right,
As | Multiply | Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd
| BitXor | BitOr | Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual
- | LAnd | LOr | Colon => Fixity::Left,
+ | LAnd | LOr => Fixity::Left,
DotDot | DotDotEq => Fixity::None,
}
}
@@ -166,8 +163,9 @@ impl AssocOp {
match *self {
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual => true,
Assign | AssignOp(_) | As | Multiply | Divide | Modulus | Add | Subtract
- | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq
- | Colon => false,
+ | ShiftLeft | ShiftRight | BitAnd | BitXor | BitOr | LAnd | LOr | DotDot | DotDotEq => {
+ false
+ }
}
}
@@ -177,7 +175,7 @@ impl AssocOp {
Assign | AssignOp(_) => true,
Less | Greater | LessEqual | GreaterEqual | Equal | NotEqual | As | Multiply
| Divide | Modulus | Add | Subtract | ShiftLeft | ShiftRight | BitAnd | BitXor
- | BitOr | LAnd | LOr | DotDot | DotDotEq | Colon => false,
+ | BitOr | LAnd | LOr | DotDot | DotDotEq => false,
}
}
@@ -202,7 +200,7 @@ impl AssocOp {
BitOr => Some(BinOpKind::BitOr),
LAnd => Some(BinOpKind::And),
LOr => Some(BinOpKind::Or),
- Assign | AssignOp(_) | As | DotDot | DotDotEq | Colon => None,
+ Assign | AssignOp(_) | As | DotDot | DotDotEq => None,
}
}
@@ -223,10 +221,9 @@ impl AssocOp {
Greater | // `{ 42 } > 3`
GreaterEqual | // `{ 42 } >= 3`
AssignOp(_) | // `{ 42 } +=`
- As | // `{ 42 } as usize`
// Equal | // `{ 42 } == { 42 }` Accepting these here would regress incorrect
- // NotEqual | // `{ 42 } != { 42 }` struct literals parser recovery.
- Colon, // `{ 42 }: usize`
+ // NotEqual | // `{ 42 } != { 42 } struct literals parser recovery.
+ As // `{ 42 } as usize`
)
}
}
@@ -254,7 +251,6 @@ pub enum ExprPrecedence {
Binary(BinOpKind),
Cast,
- Type,
Assign,
AssignOp,
@@ -269,6 +265,7 @@ pub enum ExprPrecedence {
Index,
Try,
InlineAsm,
+ OffsetOf,
Mac,
FormatArgs,
@@ -312,7 +309,6 @@ impl ExprPrecedence {
// Binop-like expr kinds, handled by `AssocOp`.
ExprPrecedence::Binary(op) => AssocOp::from_ast_binop(op).precedence() as i8,
ExprPrecedence::Cast => AssocOp::As.precedence() as i8,
- ExprPrecedence::Type => AssocOp::Colon.precedence() as i8,
ExprPrecedence::Assign |
ExprPrecedence::AssignOp => AssocOp::Assign.precedence() as i8,
@@ -335,7 +331,8 @@ impl ExprPrecedence {
| ExprPrecedence::Try
| ExprPrecedence::InlineAsm
| ExprPrecedence::Mac
- | ExprPrecedence::FormatArgs => PREC_POSTFIX,
+ | ExprPrecedence::FormatArgs
+ | ExprPrecedence::OffsetOf => PREC_POSTFIX,
// Never need parens
ExprPrecedence::Array
@@ -386,7 +383,7 @@ pub fn contains_exterior_struct_lit(value: &ast::Expr) -> bool {
// X { y: 1 } + X { y: 2 }
contains_exterior_struct_lit(lhs) || contains_exterior_struct_lit(rhs)
}
- ast::ExprKind::Await(x)
+ ast::ExprKind::Await(x, _)
| ast::ExprKind::Unary(_, x)
| ast::ExprKind::Cast(x, _)
| ast::ExprKind::Type(x, _)
diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs
index ac9b321b7..275692ad5 100644
--- a/compiler/rustc_ast/src/visit.rs
+++ b/compiler/rustc_ast/src/visit.rs
@@ -188,6 +188,9 @@ pub trait Visitor<'ast>: Sized {
fn visit_variant(&mut self, v: &'ast Variant) {
walk_variant(self, v)
}
+ fn visit_variant_discr(&mut self, discr: &'ast AnonConst) {
+ self.visit_anon_const(discr);
+ }
fn visit_label(&mut self, label: &'ast Label) {
walk_label(self, label)
}
@@ -380,7 +383,7 @@ where
visitor.visit_ident(variant.ident);
visitor.visit_vis(&variant.vis);
visitor.visit_variant_data(&variant.data);
- walk_list!(visitor, visit_anon_const, &variant.disr_expr);
+ walk_list!(visitor, visit_variant_discr, &variant.disr_expr);
walk_list!(visitor, visit_attribute, &variant.attrs);
}
@@ -864,7 +867,7 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Async(_, body) => {
visitor.visit_block(body);
}
- ExprKind::Await(expr) => visitor.visit_expr(expr),
+ ExprKind::Await(expr, _) => visitor.visit_expr(expr),
ExprKind::Assign(lhs, rhs, _) => {
visitor.visit_expr(lhs);
visitor.visit_expr(rhs);
@@ -909,6 +912,12 @@ pub fn walk_expr<'a, V: Visitor<'a>>(visitor: &mut V, expression: &'a Expr) {
ExprKind::Paren(subexpression) => visitor.visit_expr(subexpression),
ExprKind::InlineAsm(asm) => visitor.visit_inline_asm(asm),
ExprKind::FormatArgs(f) => visitor.visit_format_args(f),
+ ExprKind::OffsetOf(container, fields) => {
+ visitor.visit_ty(container);
+ for &field in fields {
+ visitor.visit_ident(field);
+ }
+ }
ExprKind::Yield(optional_expression) => {
walk_list!(visitor, visit_expr, optional_expression);
}
diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml
index eb2e82d79..6b0da2565 100644
--- a/compiler/rustc_ast_lowering/Cargo.toml
+++ b/compiler/rustc_ast_lowering/Cargo.toml
@@ -12,6 +12,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_middle = { path = "../rustc_middle" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_ast_lowering/messages.ftl b/compiler/rustc_ast_lowering/messages.ftl
index 21b2a3c22..f63a9bfcd 100644
--- a/compiler/rustc_ast_lowering/messages.ftl
+++ b/compiler/rustc_ast_lowering/messages.ftl
@@ -1,99 +1,121 @@
-ast_lowering_generic_type_with_parentheses =
- parenthesized type parameters may only be used with a `Fn` trait
- .label = only `Fn` traits may use parentheses
-
-ast_lowering_use_angle_brackets = use angle brackets instead
+ast_lowering_abi_specified_multiple_times =
+ `{$prev_name}` ABI specified multiple times
+ .label = previously specified here
+ .note = these ABIs are equivalent on the current target
-ast_lowering_invalid_abi =
- invalid ABI: found `{$abi}`
- .label = invalid ABI
- .note = invoke `{$command}` for a full list of supported calling conventions.
+ast_lowering_arbitrary_expression_in_pattern =
+ arbitrary expressions aren't allowed in patterns
-ast_lowering_invalid_abi_suggestion = did you mean
+ast_lowering_argument = argument
ast_lowering_assoc_ty_parentheses =
parenthesized generic arguments cannot be used in associated type constraints
-ast_lowering_remove_parentheses = remove these parentheses
-
-ast_lowering_misplaced_impl_trait =
- `impl Trait` only allowed in function and inherent method return types, not in {$position}
-
-ast_lowering_misplaced_assoc_ty_binding =
- associated type bounds are only allowed in where clauses and function signatures, not in {$position}
+ast_lowering_async_generators_not_supported =
+ `async` generators are not yet supported
-ast_lowering_underscore_expr_lhs_assign =
- in expressions, `_` can only be used on the left-hand side of an assignment
- .label = `_` not allowed here
+ast_lowering_async_non_move_closure_not_supported =
+ `async` non-`move` closures with parameters are not currently supported
+ .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
-ast_lowering_base_expression_double_dot =
- base expression required after `..`
- .label = add a base expression here
+ast_lowering_att_syntax_only_x86 =
+ the `att_syntax` option is only supported on x86
ast_lowering_await_only_in_async_fn_and_blocks =
`await` is only allowed inside `async` functions and blocks
.label = only allowed inside `async` functions and blocks
-ast_lowering_this_not_async = this is not `async`
+ast_lowering_bad_return_type_notation_inputs =
+ argument types not allowed with return type notation
+ .suggestion = remove the input types
-ast_lowering_generator_too_many_parameters =
- too many parameters for a generator (expected 0 or 1 parameters)
+ast_lowering_bad_return_type_notation_needs_dots =
+ return type notation arguments must be elided with `..`
+ .suggestion = add `..`
+
+ast_lowering_bad_return_type_notation_output =
+ return type not allowed with return type notation
+ .suggestion = remove the return type
+
+ast_lowering_base_expression_double_dot =
+ base expression required after `..`
+ .label = add a base expression here
+
+ast_lowering_clobber_abi_not_supported =
+ `clobber_abi` is not supported on this target
ast_lowering_closure_cannot_be_static = closures cannot be static
-ast_lowering_async_non_move_closure_not_supported =
- `async` non-`move` closures with parameters are not currently supported
- .help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
+ast_lowering_does_not_support_modifiers =
+ the `{$class_name}` register class does not support template modifiers
+
+ast_lowering_extra_double_dot =
+ `..` can only be used once per {$ctx} pattern
+ .label = can only be used once per {$ctx} pattern
ast_lowering_functional_record_update_destructuring_assignment =
functional record updates are not allowed in destructuring assignments
.suggestion = consider removing the trailing pattern
-ast_lowering_async_generators_not_supported =
- `async` generators are not yet supported
+ast_lowering_generator_too_many_parameters =
+ too many parameters for a generator (expected 0 or 1 parameters)
-ast_lowering_inline_asm_unsupported_target =
- inline assembly is unsupported on this target
+ast_lowering_generic_type_with_parentheses =
+ parenthesized type parameters may only be used with a `Fn` trait
+ .label = only `Fn` traits may use parentheses
-ast_lowering_att_syntax_only_x86 =
- the `att_syntax` option is only supported on x86
+ast_lowering_inclusive_range_with_no_end = inclusive range with no end
-ast_lowering_abi_specified_multiple_times =
- `{$prev_name}` ABI specified multiple times
- .label = previously specified here
- .note = these ABIs are equivalent on the current target
+ast_lowering_inline_asm_unsupported_target =
+ inline assembly is unsupported on this target
-ast_lowering_clobber_abi_not_supported =
- `clobber_abi` is not supported on this target
+ast_lowering_invalid_abi =
+ invalid ABI: found `{$abi}`
+ .label = invalid ABI
+ .note = invoke `{$command}` for a full list of supported calling conventions.
ast_lowering_invalid_abi_clobber_abi =
invalid ABI for `clobber_abi`
.note = the following ABIs are supported on this target: {$supported_abis}
+ast_lowering_invalid_abi_suggestion = did you mean
+
+ast_lowering_invalid_asm_template_modifier_const =
+ asm template modifiers are not allowed for `const` arguments
+
+ast_lowering_invalid_asm_template_modifier_reg_class =
+ invalid asm template modifier for this register class
+
+ast_lowering_invalid_asm_template_modifier_sym =
+ asm template modifiers are not allowed for `sym` arguments
+
ast_lowering_invalid_register =
invalid register `{$reg}`: {$error}
ast_lowering_invalid_register_class =
invalid register class `{$reg_class}`: {$error}
-ast_lowering_invalid_asm_template_modifier_reg_class =
- invalid asm template modifier for this register class
+ast_lowering_misplaced_assoc_ty_binding =
+ associated type bounds are only allowed in where clauses and function signatures, not in {$position}
-ast_lowering_argument = argument
+ast_lowering_misplaced_double_dot =
+ `..` patterns are not allowed here
+ .note = only allowed in tuple, tuple struct, and slice patterns
-ast_lowering_template_modifier = template modifier
+ast_lowering_misplaced_impl_trait =
+ `impl Trait` only allowed in function and inherent method return types, not in {$position}
-ast_lowering_support_modifiers =
- the `{$class_name}` register class supports the following template modifiers: {$modifiers}
+ast_lowering_misplaced_relax_trait_bound =
+ `?Trait` bounds are only permitted at the point where a type parameter is declared
-ast_lowering_does_not_support_modifiers =
- the `{$class_name}` register class does not support template modifiers
+ast_lowering_not_supported_for_lifetime_binder_async_closure =
+ `for<...>` binders on `async` closures are not currently supported
-ast_lowering_invalid_asm_template_modifier_const =
- asm template modifiers are not allowed for `const` arguments
+ast_lowering_previously_used_here = previously used here
-ast_lowering_invalid_asm_template_modifier_sym =
- asm template modifiers are not allowed for `sym` arguments
+ast_lowering_register1 = register `{$reg1_name}`
+
+ast_lowering_register2 = register `{$reg2_name}`
ast_lowering_register_class_only_clobber =
register class `{$reg_class_name}` can only be used as a clobber, not as an input or output
@@ -102,9 +124,7 @@ ast_lowering_register_conflict =
register `{$reg1_name}` conflicts with register `{$reg2_name}`
.help = use `lateout` instead of `out` to avoid conflict
-ast_lowering_register1 = register `{$reg1_name}`
-
-ast_lowering_register2 = register `{$reg2_name}`
+ast_lowering_remove_parentheses = remove these parentheses
ast_lowering_sub_tuple_binding =
`{$ident_name} @` is not allowed in a {$ctx}
@@ -113,26 +133,12 @@ ast_lowering_sub_tuple_binding =
ast_lowering_sub_tuple_binding_suggestion = if you don't need to use the contents of {$ident}, discard the tuple's remaining fields
-ast_lowering_extra_double_dot =
- `..` can only be used once per {$ctx} pattern
- .label = can only be used once per {$ctx} pattern
-
-ast_lowering_previously_used_here = previously used here
-
-ast_lowering_misplaced_double_dot =
- `..` patterns are not allowed here
- .note = only allowed in tuple, tuple struct, and slice patterns
-
-ast_lowering_misplaced_relax_trait_bound =
- `?Trait` bounds are only permitted at the point where a type parameter is declared
-
-ast_lowering_not_supported_for_lifetime_binder_async_closure =
- `for<...>` binders on `async` closures are not currently supported
+ast_lowering_support_modifiers =
+ the `{$class_name}` register class supports the following template modifiers: {$modifiers}
-ast_lowering_arbitrary_expression_in_pattern =
- arbitrary expressions aren't allowed in patterns
+ast_lowering_template_modifier = template modifier
-ast_lowering_inclusive_range_with_no_end = inclusive range with no end
+ast_lowering_this_not_async = this is not `async`
ast_lowering_trait_fn_async =
functions in traits cannot be declared `async`
@@ -140,14 +146,8 @@ ast_lowering_trait_fn_async =
.note = `async` trait functions are not currently supported
.note2 = consider using the `async-trait` crate: https://crates.io/crates/async-trait
-ast_lowering_bad_return_type_notation_inputs =
- argument types not allowed with return type notation
- .suggestion = remove the input types
-
-ast_lowering_bad_return_type_notation_needs_dots =
- return type notation arguments must be elided with `..`
- .suggestion = add `..`
+ast_lowering_underscore_expr_lhs_assign =
+ in expressions, `_` can only be used on the left-hand side of an assignment
+ .label = `_` not allowed here
-ast_lowering_bad_return_type_notation_output =
- return type not allowed with return type notation
- .suggestion = remove the return type
+ast_lowering_use_angle_brackets = use angle brackets instead
diff --git a/compiler/rustc_ast_lowering/src/errors.rs b/compiler/rustc_ast_lowering/src/errors.rs
index 3e9f9b436..72dc52a63 100644
--- a/compiler/rustc_ast_lowering/src/errors.rs
+++ b/compiler/rustc_ast_lowering/src/errors.rs
@@ -108,7 +108,7 @@ pub struct BaseExpressionDoubleDot {
pub struct AwaitOnlyInAsyncFnAndBlocks {
#[primary_span]
#[label]
- pub dot_await_span: Span,
+ pub await_kw_span: Span,
#[label(ast_lowering_this_not_async)]
pub item_span: Option<Span>,
}
diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs
index 1b1c4765b..5e0ab80c6 100644
--- a/compiler/rustc_ast_lowering/src/expr.rs
+++ b/compiler/rustc_ast_lowering/src/expr.rs
@@ -121,12 +121,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
LitKind::Err
}
};
- hir::ExprKind::Lit(respan(self.lower_span(e.span), lit_kind))
+ let lit = self.arena.alloc(respan(self.lower_span(e.span), lit_kind));
+ hir::ExprKind::Lit(lit)
+ }
+ ExprKind::IncludedBytes(bytes) => {
+ let lit = self.arena.alloc(respan(
+ self.lower_span(e.span),
+ LitKind::ByteStr(bytes.clone(), StrStyle::Cooked),
+ ));
+ hir::ExprKind::Lit(lit)
}
- ExprKind::IncludedBytes(bytes) => hir::ExprKind::Lit(respan(
- self.lower_span(e.span),
- LitKind::ByteStr(bytes.clone(), StrStyle::Cooked),
- )),
ExprKind::Cast(expr, ty) => {
let expr = self.lower_expr(expr);
let ty =
@@ -181,21 +185,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
- ExprKind::Await(expr) => {
- let dot_await_span = if expr.span.hi() < e.span.hi() {
- let span_with_whitespace = self
- .tcx
- .sess
- .source_map()
- .span_extend_while(expr.span, char::is_whitespace)
- .unwrap_or(expr.span);
- span_with_whitespace.shrink_to_hi().with_hi(e.span.hi())
- } else {
- // this is a recovered `await expr`
- e.span
- };
- self.lower_expr_await(dot_await_span, expr)
- }
+ ExprKind::Await(expr, await_kw_span) => self.lower_expr_await(*await_kw_span, expr),
ExprKind::Closure(box Closure {
binder,
capture_clause,
@@ -285,6 +275,13 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ExprKind::InlineAsm(self.lower_inline_asm(e.span, asm))
}
ExprKind::FormatArgs(fmt) => self.lower_format_args(e.span, fmt),
+ ExprKind::OffsetOf(container, fields) => hir::ExprKind::OffsetOf(
+ self.lower_ty(
+ container,
+ &mut ImplTraitContext::Disallowed(ImplTraitPosition::OffsetOf),
+ ),
+ self.arena.alloc_from_iter(fields.iter().map(|&ident| self.lower_ident(ident))),
+ ),
ExprKind::Struct(se) => {
let rest = match &se.rest {
StructRest::Base(e) => Some(self.lower_expr(e)),
@@ -699,18 +696,18 @@ impl<'hir> LoweringContext<'_, 'hir> {
/// }
/// }
/// ```
- fn lower_expr_await(&mut self, dot_await_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
- let full_span = expr.span.to(dot_await_span);
+ fn lower_expr_await(&mut self, await_kw_span: Span, expr: &Expr) -> hir::ExprKind<'hir> {
+ let full_span = expr.span.to(await_kw_span);
match self.generator_kind {
Some(hir::GeneratorKind::Async(_)) => {}
Some(hir::GeneratorKind::Gen) | None => {
self.tcx.sess.emit_err(AwaitOnlyInAsyncFnAndBlocks {
- dot_await_span,
+ await_kw_span,
item_span: self.current_item,
});
}
}
- let span = self.mark_span_with_reason(DesugaringKind::Await, dot_await_span, None);
+ let span = self.mark_span_with_reason(DesugaringKind::Await, await_kw_span, None);
let gen_future_span = self.mark_span_with_reason(
DesugaringKind::Await,
full_span,
@@ -847,13 +844,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
let awaitee_arm = self.arm(awaitee_pat, loop_expr);
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
- let into_future_span = self.mark_span_with_reason(
- DesugaringKind::Await,
- dot_await_span,
- self.allow_into_future.clone(),
- );
let into_future_expr = self.expr_call_lang_item_fn(
- into_future_span,
+ span,
hir::LangItem::IntoFutureIntoFuture,
arena_vec![self; expr],
Some(expr_hir_id),
@@ -1746,40 +1738,31 @@ impl<'hir> LoweringContext<'_, 'hir> {
}
pub(super) fn expr_usize(&mut self, sp: Span, value: usize) -> hir::Expr<'hir> {
- self.expr(
- sp,
- hir::ExprKind::Lit(hir::Lit {
- span: sp,
- node: ast::LitKind::Int(
- value as u128,
- ast::LitIntType::Unsigned(ast::UintTy::Usize),
- ),
- }),
- )
+ let lit = self.arena.alloc(hir::Lit {
+ span: sp,
+ node: ast::LitKind::Int(value as u128, ast::LitIntType::Unsigned(ast::UintTy::Usize)),
+ });
+ self.expr(sp, hir::ExprKind::Lit(lit))
}
pub(super) fn expr_u32(&mut self, sp: Span, value: u32) -> hir::Expr<'hir> {
- self.expr(
- sp,
- hir::ExprKind::Lit(hir::Lit {
- span: sp,
- node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
- }),
- )
+ let lit = self.arena.alloc(hir::Lit {
+ span: sp,
+ node: ast::LitKind::Int(value.into(), ast::LitIntType::Unsigned(ast::UintTy::U32)),
+ });
+ self.expr(sp, hir::ExprKind::Lit(lit))
}
pub(super) fn expr_char(&mut self, sp: Span, value: char) -> hir::Expr<'hir> {
- self.expr(sp, hir::ExprKind::Lit(hir::Lit { span: sp, node: ast::LitKind::Char(value) }))
+ let lit = self.arena.alloc(hir::Lit { span: sp, node: ast::LitKind::Char(value) });
+ self.expr(sp, hir::ExprKind::Lit(lit))
}
pub(super) fn expr_str(&mut self, sp: Span, value: Symbol) -> hir::Expr<'hir> {
- self.expr(
- sp,
- hir::ExprKind::Lit(hir::Lit {
- span: sp,
- node: ast::LitKind::Str(value, ast::StrStyle::Cooked),
- }),
- )
+ let lit = self
+ .arena
+ .alloc(hir::Lit { span: sp, node: ast::LitKind::Str(value, ast::StrStyle::Cooked) });
+ self.expr(sp, hir::ExprKind::Lit(lit))
}
pub(super) fn expr_call_mut(
diff --git a/compiler/rustc_ast_lowering/src/format.rs b/compiler/rustc_ast_lowering/src/format.rs
index c41bdc440..afcf8b15c 100644
--- a/compiler/rustc_ast_lowering/src/format.rs
+++ b/compiler/rustc_ast_lowering/src/format.rs
@@ -186,7 +186,7 @@ enum ArgumentType {
/// Generates:
///
/// ```text
-/// <core::fmt::ArgumentV1>::new_…(arg)
+/// <core::fmt::Argument>::new_…(arg)
/// ```
fn make_argument<'hir>(
ctx: &mut LoweringContext<'_, 'hir>,
@@ -220,19 +220,19 @@ fn make_argument<'hir>(
/// Generates:
///
/// ```text
-/// <core::fmt::rt::v1::Count>::Is(…)
+/// <core::fmt::rt::Count>::Is(…)
/// ```
///
/// or
///
/// ```text
-/// <core::fmt::rt::v1::Count>::Param(…)
+/// <core::fmt::rt::Count>::Param(…)
/// ```
///
/// or
///
/// ```text
-/// <core::fmt::rt::v1::Count>::Implied
+/// <core::fmt::rt::Count>::Implied
/// ```
fn make_count<'hir>(
ctx: &mut LoweringContext<'_, 'hir>,
@@ -278,13 +278,13 @@ fn make_count<'hir>(
/// Generates
///
/// ```text
-/// <core::fmt::rt::v1::Argument::new(
+/// <core::fmt::rt::Placeholder::new(
/// …usize, // position
/// '…', // fill
-/// <core::fmt::rt::v1::Alignment>::…, // alignment
+/// <core::fmt::rt::Alignment>::…, // alignment
/// …u32, // flags
-/// <core::fmt::rt::v1::Count::…>, // width
-/// <core::fmt::rt::v1::Count::…>, // precision
+/// <core::fmt::rt::Count::…>, // width
+/// <core::fmt::rt::Count::…>, // precision
/// )
/// ```
fn make_format_spec<'hir>(
@@ -327,7 +327,7 @@ fn make_format_spec<'hir>(
None => sym::Unknown,
},
);
- // This needs to match `FlagV1` in library/core/src/fmt/mod.rs.
+ // This needs to match `Flag` in library/core/src/fmt/rt.rs.
let flags: u32 = ((sign == Some(FormatSign::Plus)) as u32)
| ((sign == Some(FormatSign::Minus)) as u32) << 1
| (alternate as u32) << 2
@@ -438,7 +438,7 @@ fn expand_format_args<'hir>(
// If the args array contains exactly all the original arguments once,
// in order, we can use a simple array instead of a `match` construction.
// However, if there's a yield point in any argument except the first one,
- // we don't do this, because an ArgumentV1 cannot be kept across yield points.
+ // we don't do this, because an Argument cannot be kept across yield points.
//
// This is an optimization, speeding up compilation about 1-2% in some cases.
// See https://github.com/rust-lang/rust/pull/106770#issuecomment-1380790609
@@ -446,12 +446,35 @@ fn expand_format_args<'hir>(
&& argmap.iter().enumerate().all(|(i, (&(j, _), _))| i == j)
&& arguments.iter().skip(1).all(|arg| !may_contain_yield_point(&arg.expr));
- let args = if use_simple_array {
+ let args = if arguments.is_empty() {
+ // Generate:
+ // &<core::fmt::Argument>::none()
+ //
+ // Note:
+ // `none()` just returns `[]`. We use `none()` rather than `[]` to limit the lifetime.
+ //
+ // This makes sure that this still fails to compile, even when the argument is inlined:
+ //
+ // ```
+ // let f = format_args!("{}", "a");
+ // println!("{f}"); // error E0716
+ // ```
+ //
+ // Cases where keeping the object around is allowed, such as `format_args!("a")`,
+ // are handled above by the `allow_const` case.
+ let none_fn = ctx.arena.alloc(ctx.expr_lang_item_type_relative(
+ macsp,
+ hir::LangItem::FormatArgument,
+ sym::none,
+ ));
+ let none = ctx.expr_call(macsp, none_fn, &[]);
+ ctx.expr(macsp, hir::ExprKind::AddrOf(hir::BorrowKind::Ref, hir::Mutability::Not, none))
+ } else if use_simple_array {
// Generate:
// &[
- // <core::fmt::ArgumentV1>::new_display(&arg0),
- // <core::fmt::ArgumentV1>::new_lower_hex(&arg1),
- // <core::fmt::ArgumentV1>::new_debug(&arg2),
+ // <core::fmt::Argument>::new_display(&arg0),
+ // <core::fmt::Argument>::new_lower_hex(&arg1),
+ // <core::fmt::Argument>::new_debug(&arg2),
// …
// ]
let elements: Vec<_> = arguments
@@ -477,9 +500,9 @@ fn expand_format_args<'hir>(
// Generate:
// &match (&arg0, &arg1, &…) {
// args => [
- // <core::fmt::ArgumentV1>::new_display(args.0),
- // <core::fmt::ArgumentV1>::new_lower_hex(args.1),
- // <core::fmt::ArgumentV1>::new_debug(args.0),
+ // <core::fmt::Argument>::new_display(args.0),
+ // <core::fmt::Argument>::new_lower_hex(args.1),
+ // <core::fmt::Argument>::new_debug(args.0),
// …
// ]
// }
@@ -583,7 +606,7 @@ fn may_contain_yield_point(e: &ast::Expr) -> bool {
impl Visitor<'_> for MayContainYieldPoint {
fn visit_expr(&mut self, e: &ast::Expr) {
- if let ast::ExprKind::Await(_) | ast::ExprKind::Yield(_) = e.kind {
+ if let ast::ExprKind::Await(_, _) | ast::ExprKind::Yield(_) = e.kind {
self.0 = true;
} else {
visit::walk_expr(self, e);
diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs
index f7fe0d771..2e66c81eb 100644
--- a/compiler/rustc_ast_lowering/src/index.rs
+++ b/compiler/rustc_ast_lowering/src/index.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::LocalDefId;
use rustc_hir::definitions;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::*;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::span_bug;
use rustc_session::Session;
use rustc_span::source_map::SourceMap;
diff --git a/compiler/rustc_ast_lowering/src/item.rs b/compiler/rustc_ast_lowering/src/item.rs
index f89e254a2..08ee3761b 100644
--- a/compiler/rustc_ast_lowering/src/item.rs
+++ b/compiler/rustc_ast_lowering/src/item.rs
@@ -12,7 +12,7 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
use rustc_hir::PredicateOrigin;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::ty::{ResolverAstLowering, TyCtxt};
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::source_map::DesugaringKind;
@@ -83,15 +83,14 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
impl_trait_bounds: Vec::new(),
allow_try_trait: Some([sym::try_trait_v2, sym::yeet_desugar_details][..].into()),
allow_gen_future: Some([sym::gen_future, sym::closure_track_caller][..].into()),
- allow_into_future: Some([sym::into_future][..].into()),
generics_def_id_map: Default::default(),
};
lctx.with_hir_id_owner(owner, |lctx| f(lctx));
for (def_id, info) in lctx.children {
- self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
- debug_assert!(matches!(self.owners[def_id], hir::MaybeOwner::Phantom));
- self.owners[def_id] = info;
+ let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ debug_assert!(matches!(owner, hir::MaybeOwner::Phantom));
+ *owner = info;
}
}
@@ -99,8 +98,8 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
&mut self,
def_id: LocalDefId,
) -> hir::MaybeOwner<&'hir hir::OwnerInfo<'hir>> {
- self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
- if let hir::MaybeOwner::Phantom = self.owners[def_id] {
+ let owner = self.owners.ensure_contains_elem(def_id, || hir::MaybeOwner::Phantom);
+ if let hir::MaybeOwner::Phantom = owner {
let node = self.ast_index[def_id];
match node {
AstOwner::NonOwner => {}
@@ -138,12 +137,10 @@ impl<'a, 'hir> ItemLowerer<'a, 'hir> {
// Evaluate with the lifetimes in `params` in-scope.
// This is used to track which lifetimes have already been defined,
// and which need to be replicated when lowering an async fn.
- match parent_hir.node().expect_item().kind {
- hir::ItemKind::Impl(hir::Impl { of_trait, .. }) => {
- lctx.is_in_trait_impl = of_trait.is_some();
- }
- _ => {}
- };
+
+ if let hir::ItemKind::Impl(impl_) = parent_hir.node().expect_item().kind {
+ lctx.is_in_trait_impl = impl_.of_trait.is_some();
+ }
match ctxt {
AssocCtxt::Trait => hir::OwnerNode::TraitItem(lctx.lower_trait_item(item)),
@@ -308,7 +305,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
);
this.arena.alloc(this.ty(span, hir::TyKind::Err(guar)))
}
- Some(ty) => this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy),
+ Some(ty) => this.lower_ty(
+ ty,
+ &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: false },
+ ),
},
);
hir::ItemKind::TyAlias(ty, generics)
@@ -445,7 +445,8 @@ impl<'hir> LoweringContext<'_, 'hir> {
ItemKind::MacroDef(MacroDef { body, macro_rules }) => {
let body = P(self.lower_delim_args(body));
let macro_kind = self.resolver.decl_macro_kind(self.local_def_id(id));
- hir::ItemKind::Macro(ast::MacroDef { body, macro_rules: *macro_rules }, macro_kind)
+ let macro_def = self.arena.alloc(ast::MacroDef { body, macro_rules: *macro_rules });
+ hir::ItemKind::Macro(macro_def, macro_kind)
}
ItemKind::MacCall(..) => {
panic!("`TyMac` should have been expanded by now")
@@ -854,7 +855,10 @@ impl<'hir> LoweringContext<'_, 'hir> {
hir::ImplItemKind::Type(ty)
}
Some(ty) => {
- let ty = this.lower_ty(ty, &ImplTraitContext::TypeAliasesOpaqueTy);
+ let ty = this.lower_ty(
+ ty,
+ &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty: true },
+ );
hir::ImplItemKind::Type(ty)
}
},
diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs
index f7ae96b7c..8d4f96639 100644
--- a/compiler/rustc_ast_lowering/src/lib.rs
+++ b/compiler/rustc_ast_lowering/src/lib.rs
@@ -55,13 +55,13 @@ use rustc_data_structures::sync::Lrc;
use rustc_errors::{
DiagnosticArgFromDisplay, DiagnosticMessage, Handler, StashKey, SubdiagnosticMessage,
};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res};
-use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
+use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_hir::{ConstArg, GenericArg, ItemLocalId, ParamName, TraitCandidate};
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
-use rustc_macros::fluent_messages;
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::{
span_bug,
ty::{ResolverAstLowering, TyCtxt},
@@ -136,7 +136,6 @@ struct LoweringContext<'a, 'hir> {
allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
- allow_into_future: Option<Lrc<[Symbol]>>,
/// Mapping from generics `def_id`s to TAIT generics `def_id`s.
/// For each captured lifetime (e.g., 'a), we create a new lifetime parameter that is a generic
@@ -248,7 +247,7 @@ enum ImplTraitContext {
in_trait: bool,
},
/// Impl trait in type aliases.
- TypeAliasesOpaqueTy,
+ TypeAliasesOpaqueTy { in_assoc_ty: bool },
/// `impl Trait` is unstably accepted in this position.
FeatureGated(ImplTraitPosition, Symbol),
/// `impl Trait` is not accepted in this position.
@@ -283,6 +282,7 @@ enum ImplTraitPosition {
FieldTy,
Cast,
ImplSelf,
+ OffsetOf,
}
impl std::fmt::Display for ImplTraitPosition {
@@ -313,6 +313,7 @@ impl std::fmt::Display for ImplTraitPosition {
ImplTraitPosition::FieldTy => "field types",
ImplTraitPosition::Cast => "cast types",
ImplTraitPosition::ImplSelf => "impl headers",
+ ImplTraitPosition::OffsetOf => "`offset_of!` params",
};
write!(f, "{name}")
@@ -332,10 +333,7 @@ enum FnDeclKind {
impl FnDeclKind {
fn param_impl_trait_allowed(&self) -> bool {
- match self {
- FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait => true,
- _ => false,
- }
+ matches!(self, FnDeclKind::Fn | FnDeclKind::Inherent | FnDeclKind::Impl | FnDeclKind::Trait)
}
fn return_impl_trait_allowed(&self, tcx: TyCtxt<'_>) -> bool {
@@ -371,8 +369,8 @@ fn index_crate<'a>(
krate: &'a Crate,
) -> IndexVec<LocalDefId, AstOwner<'a>> {
let mut indexer = Indexer { node_id_to_def_id, index: IndexVec::new() };
- indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner);
- indexer.index[CRATE_DEF_ID] = AstOwner::Crate(krate);
+ *indexer.index.ensure_contains_elem(CRATE_DEF_ID, || AstOwner::NonOwner) =
+ AstOwner::Crate(krate);
visit::walk_crate(&mut indexer, krate);
return indexer.index;
@@ -389,22 +387,21 @@ fn index_crate<'a>(
fn visit_item(&mut self, item: &'a ast::Item) {
let def_id = self.node_id_to_def_id[&item.id];
- self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
- self.index[def_id] = AstOwner::Item(item);
+ *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) = AstOwner::Item(item);
visit::walk_item(self, item)
}
fn visit_assoc_item(&mut self, item: &'a ast::AssocItem, ctxt: visit::AssocCtxt) {
let def_id = self.node_id_to_def_id[&item.id];
- self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
- self.index[def_id] = AstOwner::AssocItem(item, ctxt);
+ *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
+ AstOwner::AssocItem(item, ctxt);
visit::walk_assoc_item(self, item, ctxt);
}
fn visit_foreign_item(&mut self, item: &'a ast::ForeignItem) {
let def_id = self.node_id_to_def_id[&item.id];
- self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner);
- self.index[def_id] = AstOwner::ForeignItem(item);
+ *self.index.ensure_contains_elem(def_id, || AstOwner::NonOwner) =
+ AstOwner::ForeignItem(item);
visit::walk_foreign_item(self, item);
}
}
@@ -438,6 +435,7 @@ pub fn lower_to_hir(tcx: TyCtxt<'_>, (): ()) -> hir::Crate<'_> {
// Queries that borrow `resolver_for_lowering`.
tcx.ensure_with_value().output_filenames(());
tcx.ensure_with_value().early_lint_checks(());
+ tcx.ensure_with_value().debugger_visualizers(LOCAL_CRATE);
let (mut resolver, krate) = tcx.resolver_for_lowering(()).steal();
let ast_index = index_crate(&resolver.node_id_to_def_id, &krate);
@@ -1193,13 +1191,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// parsing. We try to resolve that ambiguity by attempting resolution in both the
// type and value namespaces. If we resolved the path in the value namespace, we
// transform it into a generic const argument.
- TyKind::Path(qself, path) => {
+ TyKind::Path(None, path) => {
if let Some(res) = self
.resolver
.get_partial_res(ty.id)
.and_then(|partial_res| partial_res.full_res())
{
- if !res.matches_ns(Namespace::TypeNS) {
+ if !res.matches_ns(Namespace::TypeNS)
+ && path.is_potential_trivial_const_arg()
+ {
debug!(
"lower_generic_arg: Lowering type argument as const argument: {:?}",
ty,
@@ -1221,7 +1221,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
let path_expr = Expr {
id: ty.id,
- kind: ExprKind::Path(qself.clone(), path.clone()),
+ kind: ExprKind::Path(None, path.clone()),
span,
attrs: AttrVec::new(),
tokens: None,
@@ -1371,13 +1371,17 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
this.arena.alloc_from_iter(bounds.iter().filter_map(|bound| match bound {
GenericBound::Trait(
ty,
- TraitBoundModifier::None | TraitBoundModifier::MaybeConst,
+ TraitBoundModifier::None
+ | TraitBoundModifier::MaybeConst
+ | TraitBoundModifier::Negative,
) => Some(this.lower_poly_trait_ref(ty, itctx)),
// `~const ?Bound` will cause an error during AST validation
// anyways, so treat it like `?Bound` as compilation proceeds.
GenericBound::Trait(
_,
- TraitBoundModifier::Maybe | TraitBoundModifier::MaybeConstMaybe,
+ TraitBoundModifier::Maybe
+ | TraitBoundModifier::MaybeConstMaybe
+ | TraitBoundModifier::MaybeConstNegative,
) => None,
GenericBound::Outlives(lifetime) => {
if lifetime_bound.is_none() {
@@ -1404,14 +1408,15 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
*in_trait,
itctx,
),
- ImplTraitContext::TypeAliasesOpaqueTy => self.lower_opaque_impl_trait(
- span,
- hir::OpaqueTyOrigin::TyAlias,
- *def_node_id,
- bounds,
- false,
- itctx,
- ),
+ &ImplTraitContext::TypeAliasesOpaqueTy { in_assoc_ty } => self
+ .lower_opaque_impl_trait(
+ span,
+ hir::OpaqueTyOrigin::TyAlias { in_assoc_ty },
+ *def_node_id,
+ bounds,
+ false,
+ itctx,
+ ),
ImplTraitContext::Universal => {
let span = t.span;
self.create_def(
@@ -1420,7 +1425,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
DefPathData::ImplTrait,
span,
);
- let ident = Ident::from_str_and_span(&pprust::ty_to_string(t), span);
+
+ // HACK: pprust breaks strings with newlines when the type
+ // gets too long. We don't want these to show up in compiler
+ // output or built artifacts, so replace them here...
+ // Perhaps we should instead format APITs more robustly.
+ let ident = Ident::from_str_and_span(
+ &pprust::ty_to_string(t).replace('\n', " "),
+ span,
+ );
+
let (param, bounds, path) = self.lower_universal_param_and_bounds(
*def_node_id,
span,
@@ -1476,6 +1490,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
/// Given a function definition like:
///
/// ```rust
+ /// use std::fmt::Debug;
+ ///
/// fn test<'a, T: Debug>(x: &'a T) -> impl Debug + 'a {
/// x
/// }
@@ -1483,13 +1499,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
///
/// we will create a TAIT definition in the HIR like
///
- /// ```
+ /// ```rust,ignore (pseudo-Rust)
/// type TestReturn<'a, T, 'x> = impl Debug + 'x
/// ```
///
/// and return a type like `TestReturn<'static, T, 'a>`, so that the function looks like:
///
- /// ```rust
+ /// ```rust,ignore (pseudo-Rust)
/// fn test<'a, T: Debug>(x: &'a T) -> TestReturn<'static, T, 'a>
/// ```
///
@@ -1529,13 +1545,16 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
// If this came from a TAIT (as opposed to a function that returns an RPIT), we only want
// to capture the lifetimes that appear in the bounds. So visit the bounds to find out
// exactly which ones those are.
- let lifetimes_to_remap = if origin == hir::OpaqueTyOrigin::TyAlias {
- // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
- Vec::new()
- } else {
- // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
- // we only keep the lifetimes that appear in the `impl Debug` itself:
- lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+ let lifetimes_to_remap = match origin {
+ hir::OpaqueTyOrigin::TyAlias { .. } => {
+ // in a TAIT like `type Foo<'a> = impl Foo<'a>`, we don't keep all the lifetime parameters
+ Vec::new()
+ }
+ hir::OpaqueTyOrigin::AsyncFn(..) | hir::OpaqueTyOrigin::FnReturn(..) => {
+ // in fn return position, like the `fn test<'a>() -> impl Debug + 'a` example,
+ // we only keep the lifetimes that appear in the `impl Debug` itself:
+ lifetime_collector::lifetimes_in_bounds(&self.resolver, bounds)
+ }
};
debug!(?lifetimes_to_remap);
@@ -2424,11 +2443,20 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
TraitBoundModifier::None => hir::TraitBoundModifier::None,
TraitBoundModifier::MaybeConst => hir::TraitBoundModifier::MaybeConst,
+ TraitBoundModifier::Negative => {
+ if self.tcx.features().negative_bounds {
+ hir::TraitBoundModifier::Negative
+ } else {
+ hir::TraitBoundModifier::None
+ }
+ }
+
// `MaybeConstMaybe` will cause an error during AST validation, but we need to pick a
// placeholder for compilation to proceed.
TraitBoundModifier::MaybeConstMaybe | TraitBoundModifier::Maybe => {
hir::TraitBoundModifier::Maybe
}
+ TraitBoundModifier::MaybeConstNegative => hir::TraitBoundModifier::MaybeConst,
}
}
diff --git a/compiler/rustc_ast_lowering/src/path.rs b/compiler/rustc_ast_lowering/src/path.rs
index 8eb84c036..441282c05 100644
--- a/compiler/rustc_ast_lowering/src/path.rs
+++ b/compiler/rustc_ast_lowering/src/path.rs
@@ -136,7 +136,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
self.diagnostic().span_bug(
p.span,
- &format!(
+ format!(
"lower_qpath: no final extension segment in {}..{}",
proj_start,
p.segments.len()
diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml
index 8bd212073..eb7361235 100644
--- a/compiler/rustc_ast_passes/Cargo.toml
+++ b/compiler/rustc_ast_passes/Cargo.toml
@@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_macros = { path = "../rustc_macros" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_ast_passes/messages.ftl b/compiler/rustc_ast_passes/messages.ftl
index a349fe6a3..2f0ac0c2b 100644
--- a/compiler/rustc_ast_passes/messages.ftl
+++ b/compiler/rustc_ast_passes/messages.ftl
@@ -1,64 +1,3 @@
-ast_passes_forbidden_let =
- `let` expressions are not supported here
- .note = only supported directly in conditions of `if` and `while` expressions
- .not_supported_or = `||` operators are not supported in let chain expressions
- .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
-
-ast_passes_forbidden_let_stable =
- expected expression, found statement (`let`)
- .note = variable declaration using `let` is a statement
-
-ast_passes_deprecated_where_clause_location =
- where clause not allowed here
-
-ast_passes_keyword_lifetime =
- lifetimes cannot use keyword names
-
-ast_passes_invalid_label =
- invalid label name `{$name}`
-
-ast_passes_visibility_not_permitted =
- visibility qualifiers are not permitted here
- .enum_variant = enum variants and their fields always share the visibility of the enum they are in
- .trait_impl = trait items always share the visibility of their trait
- .individual_impl_items = place qualifiers on individual impl items instead
- .individual_foreign_items = place qualifiers on individual foreign items instead
-
-ast_passes_trait_fn_const =
- functions in traits cannot be declared const
- .label = functions in traits cannot be const
-
-ast_passes_forbidden_lifetime_bound =
- lifetime bounds cannot be used in this context
-
-ast_passes_forbidden_non_lifetime_param =
- only lifetime parameters can be used in this context
-
-ast_passes_fn_param_too_many =
- function can not have more than {$max_num_args} arguments
-
-ast_passes_fn_param_c_var_args_only =
- C-variadic function must be declared with at least one named argument
-
-ast_passes_fn_param_c_var_args_not_last =
- `...` must be the last argument of a C-variadic function
-
-ast_passes_fn_param_doc_comment =
- documentation comments cannot be applied to function parameters
- .label = doc comments are not allowed here
-
-ast_passes_fn_param_forbidden_attr =
- allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
-
-ast_passes_fn_param_forbidden_self =
- `self` parameter is only allowed in associated functions
- .label = not semantically valid as function parameter
- .note = associated functions are those in `impl` or `trait` definitions
-
-ast_passes_forbidden_default =
- `default` is only allowed on items in trait impls
- .label = `default` because of this
-
ast_passes_assoc_const_without_body =
associated constant in `impl` without body
.suggestion = provide a definition for the constant
@@ -71,36 +10,73 @@ ast_passes_assoc_type_without_body =
associated type in `impl` without body
.suggestion = provide a definition for the type
+ast_passes_at_least_one_trait = at least one trait must be specified
+
+ast_passes_auto_generic = auto traits cannot have generic parameters
+ .label = auto trait cannot have generic parameters
+ .suggestion = remove the parameters
+
+ast_passes_auto_items = auto traits cannot have associated items
+ .label = {ast_passes_auto_items}
+ .suggestion = remove these associated items
+
+ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
+ .label = {ast_passes_auto_super_lifetime}
+ .suggestion = remove the super traits or lifetime bounds
+
+ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
+
+ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
+ .cannot_have = cannot have a body
+ .invalid = the invalid body
+ .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
+
+ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
+
+ast_passes_const_and_async = functions cannot be both `const` and `async`
+ .const = `const` because of this
+ .async = `async` because of this
+ .label = {""}
+
ast_passes_const_without_body =
free constant item without body
.suggestion = provide a definition for the constant
-ast_passes_static_without_body =
- free static item without body
- .suggestion = provide a definition for the static
+ast_passes_constraint_on_negative_bound =
+ associated type constraints not allowed on negative bounds
-ast_passes_ty_alias_without_body =
- free type alias without body
- .suggestion = provide a definition for the type
+ast_passes_deprecated_where_clause_location =
+ where clause not allowed here
-ast_passes_fn_without_body =
- free function without a body
- .suggestion = provide a definition for the function
+ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
+ .label = not supported
+ .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
+ .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
+ .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
ast_passes_extern_block_suggestion = if you meant to declare an externally defined function, use an `extern` block
-ast_passes_bound_in_context = bounds on `type`s in {$ctx} have no effect
+ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
+ .label = in this `extern` block
+ .suggestion = remove the qualifiers
+
+ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
+ .label = in this `extern` block
+ .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
+
+ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
ast_passes_extern_types_cannot = `type`s inside `extern` blocks cannot have {$descr}
.suggestion = remove the {$remove_descr}
.label = `extern` block begins here
-ast_passes_extern_keyword_link = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
-ast_passes_body_in_extern = incorrect `{$kind}` inside `extern` block
- .cannot_have = cannot have a body
- .invalid = the invalid body
- .existing = `extern` blocks define existing foreign {$kind}s and {$kind}s inside of them cannot have a body
+ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
+ .suggestion = remove the attribute
+ .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
+
+ast_passes_fieldless_union = unions cannot have zero fields
ast_passes_fn_body_extern = incorrect function inside `extern` block
.cannot_have = cannot have a body
@@ -108,35 +84,50 @@ ast_passes_fn_body_extern = incorrect function inside `extern` block
.help = you might have meant to write a function accessible through FFI, which can be done by writing `extern fn` outside of the `extern` block
.label = `extern` blocks define existing foreign functions and functions inside of them cannot have a body
-ast_passes_extern_fn_qualifiers = functions in `extern` blocks cannot have qualifiers
- .label = in this `extern` block
- .suggestion = remove the qualifiers
+ast_passes_fn_param_c_var_args_not_last =
+ `...` must be the last argument of a C-variadic function
-ast_passes_extern_item_ascii = items in `extern` blocks cannot use non-ascii identifiers
- .label = in this `extern` block
- .note = this limitation may be lifted in the future; see issue #83942 <https://github.com/rust-lang/rust/issues/83942> for more information
+ast_passes_fn_param_c_var_args_only =
+ C-variadic function must be declared with at least one named argument
-ast_passes_bad_c_variadic = only foreign or `unsafe extern "C"` functions may be C-variadic
+ast_passes_fn_param_doc_comment =
+ documentation comments cannot be applied to function parameters
+ .label = doc comments are not allowed here
-ast_passes_item_underscore = `{$kind}` items in this context need a name
- .label = `_` is not a valid name for this `{$kind}` item
+ast_passes_fn_param_forbidden_attr =
+ allow, cfg, cfg_attr, deny, expect, forbid, and warn are the only allowed built-in attributes in function parameters
-ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
+ast_passes_fn_param_forbidden_self =
+ `self` parameter is only allowed in associated functions
+ .label = not semantically valid as function parameter
+ .note = associated functions are those in `impl` or `trait` definitions
-ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
- .help = consider using the `#[path]` attribute to specify filesystem path
+ast_passes_fn_param_too_many =
+ function can not have more than {$max_num_args} arguments
-ast_passes_auto_generic = auto traits cannot have generic parameters
- .label = auto trait cannot have generic parameters
- .suggestion = remove the parameters
+ast_passes_fn_without_body =
+ free function without a body
+ .suggestion = provide a definition for the function
-ast_passes_auto_super_lifetime = auto traits cannot have super traits or lifetime bounds
- .label = {ast_passes_auto_super_lifetime}
- .suggestion = remove the super traits or lifetime bounds
+ast_passes_forbidden_default =
+ `default` is only allowed on items in trait impls
+ .label = `default` because of this
-ast_passes_auto_items = auto traits cannot have associated items
- .label = {ast_passes_auto_items}
- .suggestion = remove these associated items
+ast_passes_forbidden_let =
+ `let` expressions are not supported here
+ .note = only supported directly in conditions of `if` and `while` expressions
+ .not_supported_or = `||` operators are not supported in let chain expressions
+ .not_supported_parentheses = `let`s wrapped in parentheses are not supported in a context with let chains
+
+ast_passes_forbidden_let_stable =
+ expected expression, found statement (`let`)
+ .note = variable declaration using `let` is a statement
+
+ast_passes_forbidden_lifetime_bound =
+ lifetime bounds cannot be used in this context
+
+ast_passes_forbidden_non_lifetime_param =
+ only lifetime parameters can be used in this context
ast_passes_generic_before_constraints = generic arguments must come before the first constraint
.constraints = {$constraint_len ->
@@ -156,82 +147,97 @@ ast_passes_generic_before_constraints = generic arguments must come before the f
*[other] arguments
}
-ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
-
-ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
+ast_passes_generic_default_trailing = generic parameters with a default must be trailing
ast_passes_impl_trait_path = `impl Trait` is not allowed in path parameters
+ast_passes_incompatible_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
+ .help = remove one of these features
+
+ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
+ .because = {$annotation} because of this
+ .type = inherent impl for this type
+ .only_trait = only trait implementations may be annotated with {$annotation}
+
+ast_passes_invalid_label =
+ invalid label name `{$name}`
+
+ast_passes_item_underscore = `{$kind}` items in this context need a name
+ .label = `_` is not a valid name for this `{$kind}` item
+
+ast_passes_keyword_lifetime =
+ lifetimes cannot use keyword names
+
+ast_passes_module_nonascii = trying to load file for module `{$name}` with non-ascii identifier name
+ .help = consider using the `#[path]` attribute to specify filesystem path
+
+ast_passes_negative_bound_not_supported =
+ negative bounds are not supported
+
ast_passes_nested_impl_trait = nested `impl Trait` is not allowed
.outer = outer `impl Trait`
.inner = nested `impl Trait` here
-ast_passes_at_least_one_trait = at least one trait must be specified
-
-ast_passes_extern_without_abi = extern declarations without an explicit ABI are deprecated
+ast_passes_nested_lifetimes = nested quantification of lifetimes
-ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
- .suggestion = reorder the parameters: lifetimes, then consts and types
+ast_passes_nomangle_ascii = `#[no_mangle]` requires ASCII identifier
ast_passes_obsolete_auto = `impl Trait for .. {"{}"}` is an obsolete syntax
.help = use `auto trait Trait {"{}"}` instead
-ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
- .negative = negative because of this
- .unsafe = unsafe because of this
+ast_passes_optional_const_exclusive = `~const` and `{$modifier}` are mutually exclusive
-ast_passes_inherent_cannot_be = inherent impls cannot be {$annotation}
- .because = {$annotation} because of this
- .type = inherent impl for this type
- .only_trait = only trait implementations may be annotated with {$annotation}
+ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
-ast_passes_unsafe_item = {$kind} cannot be declared unsafe
+ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
+ .note = traits are `?{$path_str}` by default
-ast_passes_fieldless_union = unions cannot have zero fields
+ast_passes_out_of_order_params = {$param_ord} parameters must be declared prior to {$max_param} parameters
+ .suggestion = reorder the parameters: lifetimes, then consts and types
-ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
- .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
+ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
+ .label = pattern not allowed in function without body
-ast_passes_generic_default_trailing = generic parameters with a default must be trailing
+ast_passes_pattern_in_fn_pointer = patterns aren't allowed in function pointer types
-ast_passes_nested_lifetimes = nested quantification of lifetimes
+ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
+ .label = pattern not allowed in foreign function
-ast_passes_optional_trait_supertrait = `?Trait` is not permitted in supertraits
- .note = traits are `?{$path_str}` by default
+ast_passes_show_span = {$msg}
-ast_passes_optional_trait_object = `?Trait` is not permitted in trait object types
+ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
+
+ast_passes_static_without_body =
+ free static item without body
+ .suggestion = provide a definition for the static
ast_passes_tilde_const_disallowed = `~const` is not allowed here
.trait = trait objects cannot have `~const` trait bounds
.closure = closures cannot have `~const` trait bounds
.function = this function is not `const`, so it cannot have `~const` trait bounds
-ast_passes_optional_const_exclusive = `~const` and `?` are mutually exclusive
-
-ast_passes_const_and_async = functions cannot be both `const` and `async`
- .const = `const` because of this
- .async = `async` because of this
- .label = {""}
-
-ast_passes_pattern_in_foreign = patterns aren't allowed in foreign function declarations
- .label = pattern not allowed in foreign function
+ast_passes_trait_fn_const =
+ functions in traits cannot be declared const
+ .label = functions in traits cannot be const
-ast_passes_pattern_in_bodiless = patterns aren't allowed in functions without bodies
- .label = pattern not allowed in function without body
+ast_passes_trait_object_single_bound = only a single explicit lifetime bound is permitted
-ast_passes_equality_in_where = equality constraints are not yet supported in `where` clauses
- .label = not supported
- .suggestion = if `{$ident}` is an associated type you're trying to set, use the associated type binding syntax
- .suggestion_path = if `{$trait_segment}::{$potential_assoc}` is an associated type you're trying to set, use the associated type binding syntax
- .note = see issue #20041 <https://github.com/rust-lang/rust/issues/20041> for more information
+ast_passes_ty_alias_without_body =
+ free type alias without body
+ .suggestion = provide a definition for the type
-ast_passes_stability_outside_std = stability attributes may not be used outside of the standard library
+ast_passes_unsafe_item = {$kind} cannot be declared unsafe
-ast_passes_feature_on_non_nightly = `#![feature]` may not be used on the {$channel} release channel
- .suggestion = remove the attribute
- .stable_since = the feature `{$name}` has been stable since `{$since}` and no longer requires an attribute to enable
+ast_passes_unsafe_negative_impl = negative impls cannot be unsafe
+ .negative = negative because of this
+ .unsafe = unsafe because of this
-ast_passes_incompatbile_features = `{$f1}` and `{$f2}` are incompatible, using them at the same time is not allowed
- .help = remove one of these features
+ast_passes_visibility_not_permitted =
+ visibility qualifiers are not permitted here
+ .enum_variant = enum variants and their fields always share the visibility of the enum they are in
+ .trait_impl = trait items always share the visibility of their trait
+ .individual_impl_items = place qualifiers on individual impl items instead
+ .individual_foreign_items = place qualifiers on individual foreign items instead
-ast_passes_show_span = {$msg}
+ast_passes_where_after_type_alias = where clauses are not allowed after the type for type aliases
+ .note = see issue #89122 <https://github.com/rust-lang/rust/issues/89122> for more information
diff --git a/compiler/rustc_ast_passes/src/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs
index c79626ccd..04ed27678 100644
--- a/compiler/rustc_ast_passes/src/ast_validation.rs
+++ b/compiler/rustc_ast_passes/src/ast_validation.rs
@@ -348,7 +348,7 @@ impl<'a> AstValidator<'a> {
let source_map = self.session.source_map();
let end = source_map.end_point(sp);
- if source_map.span_to_snippet(end).map(|s| s == ";").unwrap_or(false) {
+ if source_map.span_to_snippet(end).is_ok_and(|s| s == ";") {
end
} else {
sp.shrink_to_hi()
@@ -736,11 +736,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
this.visit_expr(&arm.body);
this.visit_pat(&arm.pat);
walk_list!(this, visit_attribute, &arm.attrs);
- if let Some(guard) = &arm.guard && let ExprKind::Let(_, guard_expr, _) = &guard.kind {
+ if let Some(guard) = &arm.guard {
this.with_let_management(None, |this, _| {
- this.visit_expr(guard_expr)
+ this.visit_expr(guard)
});
- return;
}
}
}
@@ -1168,12 +1167,27 @@ impl<'a> Visitor<'a> for AstValidator<'a> {
});
}
(_, TraitBoundModifier::MaybeConstMaybe) => {
- self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span()});
+ self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "?" });
+ }
+ (_, TraitBoundModifier::MaybeConstNegative) => {
+ self.err_handler().emit_err(errors::OptionalConstExclusive {span: bound.span(), modifier: "!" });
}
_ => {}
}
}
+ // Negative trait bounds are not allowed to have associated constraints
+ if let GenericBound::Trait(trait_ref, TraitBoundModifier::Negative) = bound
+ && let Some(segment) = trait_ref.trait_ref.path.segments.last()
+ && let Some(ast::GenericArgs::AngleBracketed(args)) = segment.args.as_deref()
+ {
+ for arg in &args.args {
+ if let ast::AngleBracketedArg::Constraint(constraint) = arg {
+ self.err_handler().emit_err(errors::ConstraintOnNegativeBound { span: constraint.span });
+ }
+ }
+ }
+
visit::walk_param_bound(self, bound)
}
diff --git a/compiler/rustc_ast_passes/src/errors.rs b/compiler/rustc_ast_passes/src/errors.rs
index 27bbd2379..82fe2a21d 100644
--- a/compiler/rustc_ast_passes/src/errors.rs
+++ b/compiler/rustc_ast_passes/src/errors.rs
@@ -567,6 +567,7 @@ pub enum TildeConstReason {
pub struct OptionalConstExclusive {
#[primary_span]
pub span: Span,
+ pub modifier: &'static str,
}
#[derive(Diagnostic)]
@@ -677,7 +678,7 @@ impl AddToDiagnostic for StableFeature {
}
#[derive(Diagnostic)]
-#[diag(ast_passes_incompatbile_features)]
+#[diag(ast_passes_incompatible_features)]
#[help]
pub struct IncompatibleFeatures {
#[primary_span]
@@ -693,3 +694,17 @@ pub struct ShowSpan {
pub span: Span,
pub msg: &'static str,
}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_negative_bound_not_supported)]
+pub struct NegativeBoundUnsupported {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ast_passes_constraint_on_negative_bound)]
+pub struct ConstraintOnNegativeBound {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs
index 17bcd24ee..274f931e4 100644
--- a/compiler/rustc_ast_passes/src/feature_gate.rs
+++ b/compiler/rustc_ast_passes/src/feature_gate.rs
@@ -83,7 +83,7 @@ impl<'a> PostExpansionVisitor<'a> {
&self,
const_extern_fn,
span,
- &format!("`{}` as a `const fn` ABI is unstable", abi)
+ format!("`{}` as a `const fn` ABI is unstable", abi)
),
}
}
@@ -104,7 +104,7 @@ impl<'a> PostExpansionVisitor<'a> {
if self.sess.opts.pretty.map_or(true, |ppm| ppm.needs_hir()) {
self.sess.parse_sess.span_diagnostic.delay_span_bug(
span,
- &format!(
+ format!(
"unrecognized ABI not caught in lowering: {}",
symbol_unescaped.as_str()
),
@@ -317,8 +317,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> {
match i.kind {
ast::ForeignItemKind::Fn(..) | ast::ForeignItemKind::Static(..) => {
let link_name = attr::first_attr_value_str_by_name(&i.attrs, sym::link_name);
- let links_to_llvm =
- link_name.map_or(false, |val| val.as_str().starts_with("llvm."));
+ let links_to_llvm = link_name.is_some_and(|val| val.as_str().starts_with("llvm."));
if links_to_llvm {
gate_feature_post!(
&self,
@@ -572,6 +571,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
}
};
}
+ gate_all!(c_str_literals, "`c\"..\"` literals are experimental");
gate_all!(
if_let_guard,
"`if let` guards are experimental",
@@ -602,6 +602,13 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session) {
gate_all!(yeet_expr, "`do yeet` expression is experimental");
gate_all!(dyn_star, "`dyn*` trait objects are experimental");
gate_all!(const_closures, "const closures are experimental");
+ gate_all!(builtin_syntax, "`builtin #` syntax is unstable");
+
+ if !visitor.features.negative_bounds {
+ for &span in spans.get(&sym::negative_bounds).iter().copied().flatten() {
+ sess.emit_err(errors::NegativeBoundUnsupported { span });
+ }
+ }
// All uses of `gate_all!` below this point were added in #65742,
// and subsequently disabled (with the non-early gating readded).
diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs
index e2c666604..7db413c5b 100644
--- a/compiler/rustc_ast_passes/src/lib.rs
+++ b/compiler/rustc_ast_passes/src/lib.rs
@@ -13,7 +13,7 @@
#![deny(rustc::diagnostic_outside_of_impl)]
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
pub mod ast_validation;
mod errors;
diff --git a/compiler/rustc_ast_pretty/src/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs
index c93022308..7ab8c3eab 100644
--- a/compiler/rustc_ast_pretty/src/pp.rs
+++ b/compiler/rustc_ast_pretty/src/pp.rs
@@ -360,7 +360,7 @@ impl Printer {
fn check_stack(&mut self, mut depth: usize) {
while let Some(&index) = self.scan_stack.back() {
- let mut entry = &mut self.buf[index];
+ let entry = &mut self.buf[index];
match entry.token {
Token::Begin(_) => {
if depth == 0 {
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index 849336c86..3f80728a2 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -210,6 +210,10 @@ pub fn literal_to_string(lit: token::Lit) -> String {
token::ByteStrRaw(n) => {
format!("br{delim}\"{string}\"{delim}", delim = "#".repeat(n as usize), string = symbol)
}
+ token::CStr => format!("c\"{symbol}\""),
+ token::CStrRaw(n) => {
+ format!("cr{delim}\"{symbol}\"{delim}", delim = "#".repeat(n as usize))
+ }
token::Integer | token::Float | token::Bool | token::Err => symbol.to_string(),
};
@@ -1570,12 +1574,19 @@ impl<'a> State<'a> {
GenericBound::Trait(tref, modifier) => {
match modifier {
TraitBoundModifier::None => {}
+ TraitBoundModifier::Negative => {
+ self.word("!");
+ }
TraitBoundModifier::Maybe => {
self.word("?");
}
TraitBoundModifier::MaybeConst => {
self.word_space("~const");
}
+ TraitBoundModifier::MaybeConstNegative => {
+ self.word_space("~const");
+ self.word("!");
+ }
TraitBoundModifier::MaybeConstMaybe => {
self.word_space("~const");
self.word("?");
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index 776bf5424..87c32ffce 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -341,10 +341,16 @@ impl<'a> State<'a> {
self.print_type(ty);
}
ast::ExprKind::Type(expr, ty) => {
- let prec = AssocOp::Colon.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.word_space(":");
+ self.word("type_ascribe!(");
+ self.ibox(0);
+ self.print_expr(expr);
+
+ self.word(",");
+ self.space_if_not_bol();
self.print_type(ty);
+
+ self.end();
+ self.word(")");
}
ast::ExprKind::Let(pat, scrutinee, _) => {
self.print_let(pat, scrutinee);
@@ -447,7 +453,7 @@ impl<'a> State<'a> {
self.ibox(0);
self.print_block_with_attrs(blk, attrs);
}
- ast::ExprKind::Await(expr) => {
+ ast::ExprKind::Await(expr, _) => {
self.print_expr_maybe_paren(expr, parser::PREC_POSTFIX);
self.word(".await");
}
@@ -549,6 +555,25 @@ impl<'a> State<'a> {
self.end();
self.pclose();
}
+ ast::ExprKind::OffsetOf(container, fields) => {
+ self.word("builtin # offset_of");
+ self.popen();
+ self.rbox(0, Inconsistent);
+ self.print_type(container);
+ self.word(",");
+ self.space();
+
+ if let Some((&first, rest)) = fields.split_first() {
+ self.print_ident(first);
+
+ for &field in rest {
+ self.word(".");
+ self.print_ident(field);
+ }
+ }
+ self.pclose();
+ self.end();
+ }
ast::ExprKind::MacCall(m) => self.print_mac(m),
ast::ExprKind::Paren(e) => {
self.popen();
diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml
index 6349ddf31..2c4c3a0c2 100644
--- a/compiler/rustc_attr/Cargo.toml
+++ b/compiler/rustc_attr/Cargo.toml
@@ -9,6 +9,7 @@ edition = "2021"
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_errors = { path = "../rustc_errors" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_span = { path = "../rustc_span" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_feature = { path = "../rustc_feature" }
diff --git a/compiler/rustc_attr/messages.ftl b/compiler/rustc_attr/messages.ftl
index a7f8c993d..e6cbbaf37 100644
--- a/compiler/rustc_attr/messages.ftl
+++ b/compiler/rustc_attr/messages.ftl
@@ -1,27 +1,38 @@
+attr_cfg_predicate_identifier =
+ `cfg` predicate key must be an identifier
+
+attr_deprecated_item_suggestion =
+ suggestions on deprecated items are unstable
+ .help = add `#![feature(deprecated_suggestion)]` to the crate root
+ .note = see #94785 for more details
+
attr_expected_one_cfg_pattern =
expected 1 cfg-pattern
-attr_invalid_predicate =
- invalid predicate `{$predicate}`
+attr_expected_single_version_literal =
+ expected single version literal
-attr_multiple_item =
- multiple '{$item}' items
+attr_expected_version_literal =
+ expected a version literal
+
+attr_expects_feature_list =
+ `{$name}` expects a list of feature names
+
+attr_expects_features =
+ `{$name}` expects feature names
attr_incorrect_meta_item =
incorrect meta item
-attr_unknown_meta_item =
- unknown meta item '{$item}'
- .label = expected one of {$expected}
-
-attr_missing_since =
- missing 'since'
+attr_incorrect_repr_format_align_one_arg =
+ incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
-attr_missing_note =
- missing 'note'
+attr_incorrect_repr_format_generic =
+ incorrect `repr({$repr_arg})` attribute format
+ .suggestion = use parentheses instead
-attr_multiple_stability_levels =
- multiple stability levels
+attr_incorrect_repr_format_packed_one_or_zero_arg =
+ incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
attr_invalid_issue_string =
`issue` must be a non-zero numeric string or "none"
@@ -31,17 +42,15 @@ attr_invalid_issue_string =
.pos_overflow = number too large to fit in target type
.neg_overflow = number too small to fit in target type
-attr_missing_feature =
- missing 'feature'
-
-attr_non_ident_feature =
- 'feature' is not an identifier
+attr_invalid_predicate =
+ invalid predicate `{$predicate}`
-attr_missing_issue =
- missing 'issue'
+attr_invalid_repr_align_need_arg =
+ invalid `repr(align)` attribute: `align` needs an argument
+ .suggestion = supply an argument here
-attr_incorrect_repr_format_packed_one_or_zero_arg =
- incorrect `repr(packed)` attribute format: `packed` takes exactly one parenthesized argument, or no parentheses at all
+attr_invalid_repr_generic =
+ invalid `repr({$repr_arg})` attribute: {$error_part}
attr_invalid_repr_hint_no_paren =
invalid representation hint: `{$name}` does not take a parenthesized argument list
@@ -49,59 +58,50 @@ attr_invalid_repr_hint_no_paren =
attr_invalid_repr_hint_no_value =
invalid representation hint: `{$name}` does not take a value
-attr_unsupported_literal_generic =
- unsupported literal
-attr_unsupported_literal_cfg_string =
- literal in `cfg` predicate value must be a string
-attr_unsupported_literal_deprecated_string =
- literal in `deprecated` value must be a string
-attr_unsupported_literal_deprecated_kv_pair =
- item in `deprecated` must be a key/value pair
-attr_unsupported_literal_suggestion =
- consider removing the prefix
+attr_missing_feature =
+ missing 'feature'
-attr_invalid_repr_align_need_arg =
- invalid `repr(align)` attribute: `align` needs an argument
- .suggestion = supply an argument here
+attr_missing_issue =
+ missing 'issue'
-attr_invalid_repr_generic =
- invalid `repr({$repr_arg})` attribute: {$error_part}
+attr_missing_note =
+ missing 'note'
-attr_incorrect_repr_format_align_one_arg =
- incorrect `repr(align)` attribute format: `align` takes exactly one argument in parentheses
+attr_missing_since =
+ missing 'since'
-attr_incorrect_repr_format_generic =
- incorrect `repr({$repr_arg})` attribute format
- .suggestion = use parentheses instead
+attr_multiple_item =
+ multiple '{$item}' items
-attr_rustc_promotable_pairing =
- `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
+attr_multiple_stability_levels =
+ multiple stability levels
+
+attr_non_ident_feature =
+ 'feature' is not an identifier
attr_rustc_allowed_unstable_pairing =
`rustc_allowed_through_unstable_modules` attribute must be paired with a `stable` attribute
-attr_cfg_predicate_identifier =
- `cfg` predicate key must be an identifier
-
-attr_deprecated_item_suggestion =
- suggestions on deprecated items are unstable
- .help = add `#![feature(deprecated_suggestion)]` to the crate root
- .note = see #94785 for more details
-
-attr_expected_single_version_literal =
- expected single version literal
-
-attr_expected_version_literal =
- expected a version literal
-
-attr_expects_feature_list =
- `{$name}` expects a list of feature names
-
-attr_expects_features =
- `{$name}` expects feature names
+attr_rustc_promotable_pairing =
+ `rustc_promotable` attribute must be paired with either a `rustc_const_unstable` or a `rustc_const_stable` attribute
attr_soft_no_args =
`soft` should not have any arguments
+attr_unknown_meta_item =
+ unknown meta item '{$item}'
+ .label = expected one of {$expected}
+
attr_unknown_version_literal =
unknown version literal format, assuming it refers to a future version
+
+attr_unsupported_literal_cfg_string =
+ literal in `cfg` predicate value must be a string
+attr_unsupported_literal_deprecated_kv_pair =
+ item in `deprecated` must be a key/value pair
+attr_unsupported_literal_deprecated_string =
+ literal in `deprecated` value must be a string
+attr_unsupported_literal_generic =
+ unsupported literal
+attr_unsupported_literal_suggestion =
+ consider removing the prefix
diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs
index cb217be66..372a58857 100644
--- a/compiler/rustc_attr/src/builtin.rs
+++ b/compiler/rustc_attr/src/builtin.rs
@@ -5,6 +5,7 @@ use rustc_ast::{Attribute, LitKind, MetaItem, MetaItemKind, MetaItemLit, NestedM
use rustc_ast_pretty::pprust;
use rustc_feature::{find_gated_cfg, is_builtin_attr_name, Features, GatedCfg};
use rustc_macros::HashStable_Generic;
+use rustc_session::config::ExpectedValues;
use rustc_session::lint::builtin::UNEXPECTED_CFGS;
use rustc_session::lint::BuiltinLintDiagnostics;
use rustc_session::parse::{feature_err, ParseSess};
@@ -22,8 +23,7 @@ use crate::session_diagnostics::{self, IncorrectReprFormatGenericCause};
pub const VERSION_PLACEHOLDER: &str = "CURRENT_RUSTC_VERSION";
pub fn rust_version_symbol() -> Symbol {
- let version = option_env!("CFG_VERSION").unwrap_or("<current>");
- let version = version.split(' ').next().unwrap();
+ let version = option_env!("CFG_RELEASE").unwrap_or("<current>");
Symbol::intern(&version)
}
@@ -581,32 +581,32 @@ pub fn cfg_matches(
) -> bool {
eval_condition(cfg, sess, features, &mut |cfg| {
try_gate_cfg(cfg.name, cfg.span, sess, features);
- if let Some(names_valid) = &sess.check_config.names_valid {
- if !names_valid.contains(&cfg.name) {
+ match sess.check_config.expecteds.get(&cfg.name) {
+ Some(ExpectedValues::Some(values)) if !values.contains(&cfg.value) => {
sess.buffer_lint_with_diagnostic(
UNEXPECTED_CFGS,
cfg.span,
lint_node_id,
- "unexpected `cfg` condition name",
- BuiltinLintDiagnostics::UnexpectedCfg((cfg.name, cfg.name_span), None),
+ "unexpected `cfg` condition value",
+ BuiltinLintDiagnostics::UnexpectedCfgValue(
+ (cfg.name, cfg.name_span),
+ cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+ ),
);
}
- }
- if let Some(value) = cfg.value {
- if let Some(values) = &sess.check_config.values_valid.get(&cfg.name) {
- if !values.contains(&value) {
- sess.buffer_lint_with_diagnostic(
- UNEXPECTED_CFGS,
- cfg.span,
- lint_node_id,
- "unexpected `cfg` condition value",
- BuiltinLintDiagnostics::UnexpectedCfg(
- (cfg.name, cfg.name_span),
- cfg.value_span.map(|vs| (value, vs)),
- ),
- );
- }
+ None if sess.check_config.exhaustive_names => {
+ sess.buffer_lint_with_diagnostic(
+ UNEXPECTED_CFGS,
+ cfg.span,
+ lint_node_id,
+ "unexpected `cfg` condition name",
+ BuiltinLintDiagnostics::UnexpectedCfgName(
+ (cfg.name, cfg.name_span),
+ cfg.value.map(|v| (v, cfg.value_span.unwrap())),
+ ),
+ );
}
+ _ => { /* not unexpected */ }
}
sess.config.contains(&(cfg.name, cfg.value))
})
@@ -623,7 +623,7 @@ fn gate_cfg(gated_cfg: &GatedCfg, cfg_span: Span, sess: &ParseSess, features: &F
let (cfg, feature, has_feature) = gated_cfg;
if !has_feature(features) && !cfg_span.allows_unstable(*feature) {
let explain = format!("`cfg({cfg})` is experimental and subject to change");
- feature_err(sess, *feature, cfg_span, &explain).emit();
+ feature_err(sess, *feature, cfg_span, explain).emit();
}
}
diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs
index 49818c14f..cfed2acfb 100644
--- a/compiler/rustc_attr/src/lib.rs
+++ b/compiler/rustc_attr/src/lib.rs
@@ -12,7 +12,7 @@
extern crate rustc_macros;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
mod builtin;
mod session_diagnostics;
diff --git a/compiler/rustc_baked_icu_data/Cargo.toml b/compiler/rustc_baked_icu_data/Cargo.toml
index 184fea868..d3a307675 100644
--- a/compiler/rustc_baked_icu_data/Cargo.toml
+++ b/compiler/rustc_baked_icu_data/Cargo.toml
@@ -4,11 +4,11 @@ version = "0.0.0"
edition = "2021"
[dependencies]
-icu_list = "1.1.0"
-icu_locid = "1.1.0"
-icu_provider = "1.1.0"
-icu_provider_adapters = "1.1.0"
-zerovec = "0.9.2"
+icu_list = "1.2"
+icu_locid = "1.2"
+icu_provider = "1.2"
+icu_provider_adapters = "1.2"
+zerovec = "0.9.4"
[features]
rustc_use_parallel_compiler = ['icu_provider/sync']
diff --git a/compiler/rustc_baked_icu_data/src/data/fallback/likelysubtags_v1/und.rs.data b/compiler/rustc_baked_icu_data/src/data/fallback/likelysubtags_v1/und.rs.data
index 4fd177834..e4aaf50f5 100644
--- a/compiler/rustc_baked_icu_data/src/data/fallback/likelysubtags_v1/und.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/fallback/likelysubtags_v1/und.rs.data
@@ -3,223 +3,10 @@
#[allow(unused_unsafe)]
::zerovec::ZeroMap::from_parts_unchecked(
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 97u8, 98u8, 0u8, 97u8, 98u8, 113u8, 97u8, 100u8, 112u8, 97u8, 100u8, 121u8,
- 97u8, 101u8, 0u8, 97u8, 101u8, 98u8, 97u8, 104u8, 111u8, 97u8, 106u8,
- 116u8, 97u8, 107u8, 107u8, 97u8, 108u8, 116u8, 97u8, 109u8, 0u8, 97u8,
- 112u8, 99u8, 97u8, 112u8, 100u8, 97u8, 114u8, 0u8, 97u8, 114u8, 99u8, 97u8,
- 114u8, 113u8, 97u8, 114u8, 115u8, 97u8, 114u8, 121u8, 97u8, 114u8, 122u8,
- 97u8, 115u8, 0u8, 97u8, 115u8, 101u8, 97u8, 118u8, 0u8, 97u8, 118u8, 108u8,
- 97u8, 119u8, 97u8, 98u8, 97u8, 0u8, 98u8, 97u8, 108u8, 98u8, 97u8, 112u8,
- 98u8, 97u8, 120u8, 98u8, 99u8, 113u8, 98u8, 101u8, 0u8, 98u8, 101u8, 106u8,
- 98u8, 102u8, 113u8, 98u8, 102u8, 116u8, 98u8, 102u8, 121u8, 98u8, 103u8,
- 0u8, 98u8, 103u8, 99u8, 98u8, 103u8, 110u8, 98u8, 103u8, 120u8, 98u8,
- 104u8, 98u8, 98u8, 104u8, 105u8, 98u8, 104u8, 111u8, 98u8, 106u8, 105u8,
- 98u8, 106u8, 106u8, 98u8, 108u8, 116u8, 98u8, 110u8, 0u8, 98u8, 111u8, 0u8,
- 98u8, 112u8, 121u8, 98u8, 113u8, 105u8, 98u8, 114u8, 97u8, 98u8, 114u8,
- 104u8, 98u8, 114u8, 120u8, 98u8, 115u8, 113u8, 98u8, 115u8, 116u8, 98u8,
- 116u8, 118u8, 98u8, 117u8, 97u8, 98u8, 121u8, 110u8, 99u8, 99u8, 112u8,
- 99u8, 101u8, 0u8, 99u8, 104u8, 109u8, 99u8, 104u8, 114u8, 99u8, 106u8,
- 97u8, 99u8, 106u8, 109u8, 99u8, 107u8, 98u8, 99u8, 109u8, 103u8, 99u8,
- 111u8, 112u8, 99u8, 114u8, 0u8, 99u8, 114u8, 104u8, 99u8, 114u8, 107u8,
- 99u8, 114u8, 108u8, 99u8, 115u8, 119u8, 99u8, 116u8, 100u8, 99u8, 117u8,
- 0u8, 99u8, 118u8, 0u8, 100u8, 97u8, 114u8, 100u8, 99u8, 99u8, 100u8, 103u8,
- 108u8, 100u8, 109u8, 102u8, 100u8, 111u8, 105u8, 100u8, 114u8, 104u8,
- 100u8, 114u8, 115u8, 100u8, 116u8, 121u8, 100u8, 118u8, 0u8, 100u8, 122u8,
- 0u8, 101u8, 103u8, 121u8, 101u8, 107u8, 121u8, 101u8, 108u8, 0u8, 101u8,
- 115u8, 103u8, 101u8, 116u8, 116u8, 102u8, 97u8, 0u8, 102u8, 105u8, 97u8,
- 102u8, 117u8, 98u8, 103u8, 97u8, 110u8, 103u8, 98u8, 109u8, 103u8, 98u8,
- 122u8, 103u8, 101u8, 122u8, 103u8, 103u8, 110u8, 103u8, 106u8, 107u8,
- 103u8, 106u8, 117u8, 103u8, 108u8, 107u8, 103u8, 109u8, 118u8, 103u8,
- 111u8, 102u8, 103u8, 111u8, 109u8, 103u8, 111u8, 110u8, 103u8, 111u8,
- 116u8, 103u8, 114u8, 99u8, 103u8, 114u8, 116u8, 103u8, 117u8, 0u8, 103u8,
- 118u8, 114u8, 103u8, 119u8, 99u8, 103u8, 119u8, 116u8, 104u8, 97u8, 107u8,
- 104u8, 97u8, 122u8, 104u8, 100u8, 121u8, 104u8, 101u8, 0u8, 104u8, 105u8,
- 0u8, 104u8, 108u8, 117u8, 104u8, 109u8, 100u8, 104u8, 110u8, 100u8, 104u8,
- 110u8, 101u8, 104u8, 110u8, 106u8, 104u8, 110u8, 111u8, 104u8, 111u8, 99u8,
- 104u8, 111u8, 106u8, 104u8, 115u8, 110u8, 104u8, 121u8, 0u8, 105u8, 105u8,
- 0u8, 105u8, 110u8, 104u8, 105u8, 117u8, 0u8, 105u8, 119u8, 0u8, 106u8,
- 97u8, 0u8, 106u8, 105u8, 0u8, 106u8, 109u8, 108u8, 107u8, 97u8, 0u8, 107u8,
- 97u8, 97u8, 107u8, 97u8, 119u8, 107u8, 98u8, 100u8, 107u8, 98u8, 121u8,
- 107u8, 100u8, 116u8, 107u8, 102u8, 114u8, 107u8, 102u8, 121u8, 107u8,
- 104u8, 98u8, 107u8, 104u8, 110u8, 107u8, 104u8, 116u8, 107u8, 104u8, 119u8,
- 107u8, 106u8, 103u8, 107u8, 107u8, 0u8, 107u8, 109u8, 0u8, 107u8, 110u8,
- 0u8, 107u8, 111u8, 0u8, 107u8, 111u8, 105u8, 107u8, 111u8, 107u8, 107u8,
- 113u8, 121u8, 107u8, 114u8, 99u8, 107u8, 114u8, 117u8, 107u8, 115u8, 0u8,
- 107u8, 116u8, 98u8, 107u8, 117u8, 109u8, 107u8, 118u8, 0u8, 107u8, 118u8,
- 120u8, 107u8, 120u8, 99u8, 107u8, 120u8, 108u8, 107u8, 120u8, 109u8, 107u8,
- 120u8, 112u8, 107u8, 121u8, 0u8, 107u8, 122u8, 104u8, 108u8, 97u8, 98u8,
- 108u8, 97u8, 100u8, 108u8, 97u8, 104u8, 108u8, 98u8, 101u8, 108u8, 99u8,
- 112u8, 108u8, 101u8, 112u8, 108u8, 101u8, 122u8, 108u8, 105u8, 102u8,
- 108u8, 105u8, 115u8, 108u8, 107u8, 105u8, 108u8, 109u8, 110u8, 108u8,
- 111u8, 0u8, 108u8, 114u8, 99u8, 108u8, 117u8, 122u8, 108u8, 119u8, 108u8,
- 108u8, 122u8, 104u8, 109u8, 97u8, 103u8, 109u8, 97u8, 105u8, 109u8, 100u8,
- 101u8, 109u8, 100u8, 102u8, 109u8, 100u8, 120u8, 109u8, 102u8, 97u8, 109u8,
- 103u8, 112u8, 109u8, 107u8, 0u8, 109u8, 107u8, 105u8, 109u8, 108u8, 0u8,
- 109u8, 110u8, 0u8, 109u8, 110u8, 105u8, 109u8, 110u8, 119u8, 109u8, 114u8,
- 0u8, 109u8, 114u8, 100u8, 109u8, 114u8, 106u8, 109u8, 114u8, 111u8, 109u8,
- 116u8, 114u8, 109u8, 118u8, 121u8, 109u8, 119u8, 114u8, 109u8, 119u8,
- 119u8, 109u8, 121u8, 0u8, 109u8, 121u8, 109u8, 109u8, 121u8, 118u8, 109u8,
- 121u8, 122u8, 109u8, 122u8, 110u8, 110u8, 97u8, 110u8, 110u8, 101u8, 0u8,
- 110u8, 101u8, 119u8, 110u8, 110u8, 112u8, 110u8, 111u8, 100u8, 110u8,
- 111u8, 101u8, 110u8, 111u8, 110u8, 110u8, 113u8, 111u8, 110u8, 115u8,
- 107u8, 110u8, 115u8, 116u8, 111u8, 106u8, 0u8, 111u8, 106u8, 115u8, 111u8,
- 114u8, 0u8, 111u8, 114u8, 117u8, 111u8, 115u8, 0u8, 111u8, 115u8, 97u8,
- 111u8, 116u8, 97u8, 111u8, 116u8, 107u8, 111u8, 117u8, 105u8, 112u8, 97u8,
- 0u8, 112u8, 97u8, 108u8, 112u8, 101u8, 111u8, 112u8, 104u8, 108u8, 112u8,
- 104u8, 110u8, 112u8, 107u8, 97u8, 112u8, 110u8, 116u8, 112u8, 112u8, 97u8,
- 112u8, 114u8, 97u8, 112u8, 114u8, 100u8, 112u8, 115u8, 0u8, 114u8, 97u8,
- 106u8, 114u8, 104u8, 103u8, 114u8, 105u8, 102u8, 114u8, 106u8, 115u8,
- 114u8, 107u8, 116u8, 114u8, 109u8, 116u8, 114u8, 117u8, 0u8, 114u8, 117u8,
- 101u8, 114u8, 121u8, 117u8, 115u8, 97u8, 0u8, 115u8, 97u8, 104u8, 115u8,
- 97u8, 116u8, 115u8, 97u8, 122u8, 115u8, 99u8, 107u8, 115u8, 99u8, 108u8,
- 115u8, 100u8, 0u8, 115u8, 100u8, 104u8, 115u8, 103u8, 97u8, 115u8, 103u8,
- 119u8, 115u8, 104u8, 105u8, 115u8, 104u8, 110u8, 115u8, 104u8, 117u8,
- 115u8, 105u8, 0u8, 115u8, 107u8, 114u8, 115u8, 109u8, 112u8, 115u8, 111u8,
- 103u8, 115u8, 111u8, 117u8, 115u8, 114u8, 0u8, 115u8, 114u8, 98u8, 115u8,
- 114u8, 120u8, 115u8, 119u8, 98u8, 115u8, 119u8, 118u8, 115u8, 121u8, 108u8,
- 115u8, 121u8, 114u8, 116u8, 97u8, 0u8, 116u8, 97u8, 106u8, 116u8, 99u8,
- 121u8, 116u8, 100u8, 100u8, 116u8, 100u8, 103u8, 116u8, 100u8, 104u8,
- 116u8, 101u8, 0u8, 116u8, 103u8, 0u8, 116u8, 104u8, 0u8, 116u8, 104u8,
- 108u8, 116u8, 104u8, 113u8, 116u8, 104u8, 114u8, 116u8, 105u8, 0u8, 116u8,
- 105u8, 103u8, 116u8, 107u8, 116u8, 116u8, 114u8, 119u8, 116u8, 115u8,
- 100u8, 116u8, 115u8, 102u8, 116u8, 115u8, 106u8, 116u8, 116u8, 0u8, 116u8,
- 116u8, 115u8, 116u8, 120u8, 103u8, 116u8, 120u8, 111u8, 116u8, 121u8,
- 118u8, 117u8, 100u8, 105u8, 117u8, 100u8, 109u8, 117u8, 103u8, 0u8, 117u8,
- 103u8, 97u8, 117u8, 107u8, 0u8, 117u8, 110u8, 114u8, 117u8, 110u8, 120u8,
- 117u8, 114u8, 0u8, 118u8, 97u8, 105u8, 119u8, 97u8, 108u8, 119u8, 98u8,
- 113u8, 119u8, 98u8, 114u8, 119u8, 110u8, 105u8, 119u8, 115u8, 103u8, 119u8,
- 116u8, 109u8, 119u8, 117u8, 117u8, 120u8, 99u8, 111u8, 120u8, 99u8, 114u8,
- 120u8, 108u8, 99u8, 120u8, 108u8, 100u8, 120u8, 109u8, 102u8, 120u8, 109u8,
- 110u8, 120u8, 109u8, 114u8, 120u8, 110u8, 97u8, 120u8, 110u8, 114u8, 120u8,
- 112u8, 114u8, 120u8, 115u8, 97u8, 120u8, 115u8, 114u8, 121u8, 105u8, 0u8,
- 121u8, 117u8, 101u8, 122u8, 100u8, 106u8, 122u8, 103u8, 104u8, 122u8,
- 104u8, 0u8, 122u8, 104u8, 120u8, 122u8, 107u8, 116u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"am\0ar\0as\0be\0bg\0bgcbhobn\0brxchrcv\0doiel\0fa\0gu\0he\0hi\0hy\0ja\0ka\0kk\0km\0kn\0ko\0kokks\0ky\0lo\0maimk\0ml\0mn\0mnimr\0my\0ne\0or\0pa\0ps\0rajru\0sa\0satsd\0si\0sr\0ta\0te\0tg\0th\0ti\0tt\0uk\0ur\0yuezh\0")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 67u8, 121u8, 114u8, 108u8, 67u8, 121u8, 114u8, 108u8, 84u8, 105u8, 98u8,
- 116u8, 67u8, 121u8, 114u8, 108u8, 65u8, 118u8, 115u8, 116u8, 65u8, 114u8,
- 97u8, 98u8, 65u8, 104u8, 111u8, 109u8, 65u8, 114u8, 97u8, 98u8, 88u8,
- 115u8, 117u8, 120u8, 67u8, 121u8, 114u8, 108u8, 69u8, 116u8, 104u8, 105u8,
- 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8,
- 65u8, 114u8, 109u8, 105u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8,
- 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 66u8, 101u8, 110u8,
- 103u8, 83u8, 103u8, 110u8, 119u8, 67u8, 121u8, 114u8, 108u8, 65u8, 114u8,
- 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 67u8, 121u8, 114u8, 108u8, 65u8,
- 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 66u8, 97u8, 109u8, 117u8,
- 69u8, 116u8, 104u8, 105u8, 67u8, 121u8, 114u8, 108u8, 65u8, 114u8, 97u8,
- 98u8, 84u8, 97u8, 109u8, 108u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8,
- 118u8, 97u8, 67u8, 121u8, 114u8, 108u8, 68u8, 101u8, 118u8, 97u8, 65u8,
- 114u8, 97u8, 98u8, 71u8, 114u8, 101u8, 107u8, 68u8, 101u8, 118u8, 97u8,
- 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8, 69u8, 116u8, 104u8,
- 105u8, 68u8, 101u8, 118u8, 97u8, 84u8, 97u8, 118u8, 116u8, 66u8, 101u8,
- 110u8, 103u8, 84u8, 105u8, 98u8, 116u8, 66u8, 101u8, 110u8, 103u8, 65u8,
- 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 68u8,
- 101u8, 118u8, 97u8, 66u8, 97u8, 115u8, 115u8, 69u8, 116u8, 104u8, 105u8,
- 68u8, 101u8, 118u8, 97u8, 67u8, 121u8, 114u8, 108u8, 69u8, 116u8, 104u8,
- 105u8, 67u8, 97u8, 107u8, 109u8, 67u8, 121u8, 114u8, 108u8, 67u8, 121u8,
- 114u8, 108u8, 67u8, 104u8, 101u8, 114u8, 65u8, 114u8, 97u8, 98u8, 67u8,
- 104u8, 97u8, 109u8, 65u8, 114u8, 97u8, 98u8, 83u8, 111u8, 121u8, 111u8,
- 67u8, 111u8, 112u8, 116u8, 67u8, 97u8, 110u8, 115u8, 67u8, 121u8, 114u8,
- 108u8, 67u8, 97u8, 110u8, 115u8, 67u8, 97u8, 110u8, 115u8, 67u8, 97u8,
- 110u8, 115u8, 80u8, 97u8, 117u8, 99u8, 67u8, 121u8, 114u8, 108u8, 67u8,
- 121u8, 114u8, 108u8, 67u8, 121u8, 114u8, 108u8, 65u8, 114u8, 97u8, 98u8,
- 65u8, 114u8, 97u8, 98u8, 77u8, 101u8, 100u8, 102u8, 68u8, 101u8, 118u8,
- 97u8, 77u8, 111u8, 110u8, 103u8, 69u8, 116u8, 104u8, 105u8, 68u8, 101u8,
- 118u8, 97u8, 84u8, 104u8, 97u8, 97u8, 84u8, 105u8, 98u8, 116u8, 69u8,
- 103u8, 121u8, 112u8, 75u8, 97u8, 108u8, 105u8, 71u8, 114u8, 101u8, 107u8,
- 71u8, 111u8, 110u8, 109u8, 73u8, 116u8, 97u8, 108u8, 65u8, 114u8, 97u8,
- 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 72u8, 97u8, 110u8,
- 115u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 69u8, 116u8,
- 104u8, 105u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 65u8,
- 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 69u8, 116u8, 104u8, 105u8,
- 69u8, 116u8, 104u8, 105u8, 68u8, 101u8, 118u8, 97u8, 84u8, 101u8, 108u8,
- 117u8, 71u8, 111u8, 116u8, 104u8, 67u8, 112u8, 114u8, 116u8, 66u8, 101u8,
- 110u8, 103u8, 71u8, 117u8, 106u8, 114u8, 68u8, 101u8, 118u8, 97u8, 65u8,
- 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 72u8, 97u8, 110u8, 115u8, 65u8,
- 114u8, 97u8, 98u8, 69u8, 116u8, 104u8, 105u8, 72u8, 101u8, 98u8, 114u8,
- 68u8, 101u8, 118u8, 97u8, 72u8, 108u8, 117u8, 119u8, 80u8, 108u8, 114u8,
- 100u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 72u8, 109u8,
- 110u8, 112u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 68u8,
- 101u8, 118u8, 97u8, 72u8, 97u8, 110u8, 115u8, 65u8, 114u8, 109u8, 110u8,
- 89u8, 105u8, 105u8, 105u8, 67u8, 121u8, 114u8, 108u8, 67u8, 97u8, 110u8,
- 115u8, 72u8, 101u8, 98u8, 114u8, 74u8, 112u8, 97u8, 110u8, 72u8, 101u8,
- 98u8, 114u8, 68u8, 101u8, 118u8, 97u8, 71u8, 101u8, 111u8, 114u8, 67u8,
- 121u8, 114u8, 108u8, 75u8, 97u8, 119u8, 105u8, 67u8, 121u8, 114u8, 108u8,
- 65u8, 114u8, 97u8, 98u8, 84u8, 104u8, 97u8, 105u8, 68u8, 101u8, 118u8,
- 97u8, 68u8, 101u8, 118u8, 97u8, 84u8, 97u8, 108u8, 117u8, 68u8, 101u8,
- 118u8, 97u8, 77u8, 121u8, 109u8, 114u8, 65u8, 114u8, 97u8, 98u8, 76u8,
- 97u8, 111u8, 111u8, 67u8, 121u8, 114u8, 108u8, 75u8, 104u8, 109u8, 114u8,
- 75u8, 110u8, 100u8, 97u8, 75u8, 111u8, 114u8, 101u8, 67u8, 121u8, 114u8,
- 108u8, 68u8, 101u8, 118u8, 97u8, 69u8, 116u8, 104u8, 105u8, 67u8, 121u8,
- 114u8, 108u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 69u8,
- 116u8, 104u8, 105u8, 67u8, 121u8, 114u8, 108u8, 67u8, 121u8, 114u8, 108u8,
- 65u8, 114u8, 97u8, 98u8, 69u8, 116u8, 104u8, 105u8, 68u8, 101u8, 118u8,
- 97u8, 84u8, 104u8, 97u8, 105u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8,
- 114u8, 108u8, 65u8, 114u8, 97u8, 98u8, 76u8, 105u8, 110u8, 97u8, 72u8,
- 101u8, 98u8, 114u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8, 108u8,
- 84u8, 104u8, 97u8, 105u8, 76u8, 101u8, 112u8, 99u8, 67u8, 121u8, 114u8,
- 108u8, 68u8, 101u8, 118u8, 97u8, 76u8, 105u8, 115u8, 117u8, 65u8, 114u8,
- 97u8, 98u8, 84u8, 101u8, 108u8, 117u8, 76u8, 97u8, 111u8, 111u8, 65u8,
- 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 84u8, 104u8, 97u8, 105u8, 72u8,
- 97u8, 110u8, 115u8, 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8,
- 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8, 108u8, 69u8, 116u8, 104u8,
- 105u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 67u8, 121u8,
- 114u8, 108u8, 65u8, 114u8, 97u8, 98u8, 77u8, 108u8, 121u8, 109u8, 67u8,
- 121u8, 114u8, 108u8, 66u8, 101u8, 110u8, 103u8, 77u8, 121u8, 109u8, 114u8,
- 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8, 67u8, 121u8, 114u8,
- 108u8, 77u8, 114u8, 111u8, 111u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8,
- 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 72u8, 109u8, 110u8, 112u8, 77u8,
- 121u8, 109u8, 114u8, 69u8, 116u8, 104u8, 105u8, 67u8, 121u8, 114u8, 108u8,
- 77u8, 97u8, 110u8, 100u8, 65u8, 114u8, 97u8, 98u8, 72u8, 97u8, 110u8,
- 115u8, 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8, 87u8, 99u8,
- 104u8, 111u8, 76u8, 97u8, 110u8, 97u8, 68u8, 101u8, 118u8, 97u8, 82u8,
- 117u8, 110u8, 114u8, 78u8, 107u8, 111u8, 111u8, 67u8, 97u8, 110u8, 115u8,
- 84u8, 110u8, 115u8, 97u8, 67u8, 97u8, 110u8, 115u8, 67u8, 97u8, 110u8,
- 115u8, 79u8, 114u8, 121u8, 97u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8,
- 114u8, 108u8, 79u8, 115u8, 103u8, 101u8, 65u8, 114u8, 97u8, 98u8, 79u8,
- 114u8, 107u8, 104u8, 79u8, 117u8, 103u8, 114u8, 71u8, 117u8, 114u8, 117u8,
- 80u8, 104u8, 108u8, 105u8, 88u8, 112u8, 101u8, 111u8, 65u8, 114u8, 97u8,
- 98u8, 80u8, 104u8, 110u8, 120u8, 66u8, 114u8, 97u8, 104u8, 71u8, 114u8,
- 101u8, 107u8, 68u8, 101u8, 118u8, 97u8, 75u8, 104u8, 97u8, 114u8, 65u8,
- 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8, 118u8, 97u8, 82u8,
- 111u8, 104u8, 103u8, 84u8, 102u8, 110u8, 103u8, 68u8, 101u8, 118u8, 97u8,
- 66u8, 101u8, 110u8, 103u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8,
- 108u8, 67u8, 121u8, 114u8, 108u8, 75u8, 97u8, 110u8, 97u8, 68u8, 101u8,
- 118u8, 97u8, 67u8, 121u8, 114u8, 108u8, 79u8, 108u8, 99u8, 107u8, 83u8,
- 97u8, 117u8, 114u8, 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8,
- 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 79u8, 103u8, 97u8, 109u8,
- 69u8, 116u8, 104u8, 105u8, 84u8, 102u8, 110u8, 103u8, 77u8, 121u8, 109u8,
- 114u8, 65u8, 114u8, 97u8, 98u8, 83u8, 105u8, 110u8, 104u8, 65u8, 114u8,
- 97u8, 98u8, 83u8, 97u8, 109u8, 114u8, 83u8, 111u8, 103u8, 100u8, 84u8,
- 104u8, 97u8, 105u8, 67u8, 121u8, 114u8, 108u8, 83u8, 111u8, 114u8, 97u8,
- 68u8, 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 68u8, 101u8, 118u8,
- 97u8, 66u8, 101u8, 110u8, 103u8, 83u8, 121u8, 114u8, 99u8, 84u8, 97u8,
- 109u8, 108u8, 68u8, 101u8, 118u8, 97u8, 75u8, 110u8, 100u8, 97u8, 84u8,
- 97u8, 108u8, 101u8, 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8,
- 84u8, 101u8, 108u8, 117u8, 67u8, 121u8, 114u8, 108u8, 84u8, 104u8, 97u8,
- 105u8, 68u8, 101u8, 118u8, 97u8, 68u8, 101u8, 118u8, 97u8, 68u8, 101u8,
- 118u8, 97u8, 69u8, 116u8, 104u8, 105u8, 69u8, 116u8, 104u8, 105u8, 68u8,
- 101u8, 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 71u8, 114u8, 101u8, 107u8,
- 68u8, 101u8, 118u8, 97u8, 84u8, 105u8, 98u8, 116u8, 67u8, 121u8, 114u8,
- 108u8, 84u8, 104u8, 97u8, 105u8, 84u8, 97u8, 110u8, 103u8, 84u8, 111u8,
- 116u8, 111u8, 67u8, 121u8, 114u8, 108u8, 65u8, 103u8, 104u8, 98u8, 67u8,
- 121u8, 114u8, 108u8, 65u8, 114u8, 97u8, 98u8, 85u8, 103u8, 97u8, 114u8,
- 67u8, 121u8, 114u8, 108u8, 66u8, 101u8, 110u8, 103u8, 66u8, 101u8, 110u8,
- 103u8, 65u8, 114u8, 97u8, 98u8, 86u8, 97u8, 105u8, 105u8, 69u8, 116u8,
- 104u8, 105u8, 84u8, 101u8, 108u8, 117u8, 68u8, 101u8, 118u8, 97u8, 65u8,
- 114u8, 97u8, 98u8, 71u8, 111u8, 110u8, 103u8, 68u8, 101u8, 118u8, 97u8,
- 72u8, 97u8, 110u8, 115u8, 67u8, 104u8, 114u8, 115u8, 67u8, 97u8, 114u8,
- 105u8, 76u8, 121u8, 99u8, 105u8, 76u8, 121u8, 100u8, 105u8, 71u8, 101u8,
- 111u8, 114u8, 77u8, 97u8, 110u8, 105u8, 77u8, 101u8, 114u8, 99u8, 78u8,
- 97u8, 114u8, 98u8, 68u8, 101u8, 118u8, 97u8, 80u8, 114u8, 116u8, 105u8,
- 83u8, 97u8, 114u8, 98u8, 68u8, 101u8, 118u8, 97u8, 72u8, 101u8, 98u8,
- 114u8, 72u8, 97u8, 110u8, 116u8, 65u8, 114u8, 97u8, 98u8, 84u8, 102u8,
- 110u8, 103u8, 72u8, 97u8, 110u8, 115u8, 78u8, 115u8, 104u8, 117u8, 75u8,
- 105u8, 116u8, 115u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"EthiArabBengCyrlCyrlDevaDevaBengDevaCherCyrlDevaGrekArabGujrHebrDevaArmnJpanGeorCyrlKhmrKndaKoreDevaArabCyrlLaooDevaCyrlMlymCyrlBengDevaMymrDevaOryaGuruArabDevaCyrlDevaOlckArabSinhCyrlTamlTeluCyrlThaiEthiCyrlCyrlArabHantHans")
},
)
},
@@ -227,58 +14,18 @@
#[allow(unused_unsafe)]
::zerovec::ZeroMap2d::from_parts_unchecked(
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 97u8, 122u8, 0u8, 104u8, 97u8, 0u8, 107u8, 107u8, 0u8, 107u8, 117u8, 0u8,
- 107u8, 121u8, 0u8, 109u8, 97u8, 110u8, 109u8, 110u8, 0u8, 109u8, 115u8,
- 0u8, 112u8, 97u8, 0u8, 114u8, 105u8, 102u8, 115u8, 100u8, 0u8, 115u8,
- 114u8, 0u8, 116u8, 103u8, 0u8, 117u8, 103u8, 0u8, 117u8, 110u8, 114u8,
- 117u8, 122u8, 0u8, 121u8, 117u8, 101u8, 122u8, 104u8, 0u8,
- ])
+ ::zerovec::ZeroVec::from_bytes_unchecked(
+ b"az\0ha\0kk\0ky\0mn\0ms\0pa\0sd\0sr\0tg\0uz\0yuezh\0",
+ )
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 3u8, 0u8, 0u8, 0u8, 5u8, 0u8, 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 10u8, 0u8, 0u8,
- 0u8, 12u8, 0u8, 0u8, 0u8, 13u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 15u8,
- 0u8, 0u8, 0u8, 16u8, 0u8, 0u8, 0u8, 17u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 22u8, 0u8, 0u8, 0u8, 23u8, 0u8, 0u8, 0u8, 25u8, 0u8, 0u8, 0u8, 26u8,
- 0u8, 0u8, 0u8, 28u8, 0u8, 0u8, 0u8, 29u8, 0u8, 0u8, 0u8, 44u8, 0u8, 0u8,
- 0u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"\x03\0\0\0\x05\0\0\0\t\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x0F\0\0\0\x13\0\0\0\x14\0\0\0\x16\0\0\0\x17\0\0\0&\0\0\0")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 73u8, 81u8, 0u8, 73u8, 82u8, 0u8, 82u8, 85u8, 0u8, 67u8, 77u8, 0u8, 83u8,
- 68u8, 0u8, 65u8, 70u8, 0u8, 67u8, 78u8, 0u8, 73u8, 82u8, 0u8, 77u8, 78u8,
- 0u8, 76u8, 66u8, 0u8, 67u8, 78u8, 0u8, 84u8, 82u8, 0u8, 71u8, 78u8, 0u8,
- 67u8, 78u8, 0u8, 67u8, 67u8, 0u8, 80u8, 75u8, 0u8, 78u8, 76u8, 0u8, 73u8,
- 78u8, 0u8, 77u8, 69u8, 0u8, 82u8, 79u8, 0u8, 82u8, 85u8, 0u8, 84u8, 82u8,
- 0u8, 80u8, 75u8, 0u8, 75u8, 90u8, 0u8, 77u8, 78u8, 0u8, 78u8, 80u8, 0u8,
- 65u8, 70u8, 0u8, 67u8, 78u8, 0u8, 67u8, 78u8, 0u8, 65u8, 85u8, 0u8, 66u8,
- 78u8, 0u8, 71u8, 66u8, 0u8, 71u8, 70u8, 0u8, 72u8, 75u8, 0u8, 73u8, 68u8,
- 0u8, 77u8, 79u8, 0u8, 80u8, 65u8, 0u8, 80u8, 70u8, 0u8, 80u8, 72u8, 0u8,
- 83u8, 82u8, 0u8, 84u8, 72u8, 0u8, 84u8, 87u8, 0u8, 85u8, 83u8, 0u8, 86u8,
- 78u8, 0u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"IQ\0IR\0RU\0CM\0SD\0AF\0CN\0IR\0MN\0CN\0TR\0CN\0CC\0PK\0IN\0ME\0RO\0RU\0TR\0PK\0AF\0CN\0CN\0AU\0BN\0GB\0GF\0HK\0ID\0MO\0PA\0PF\0PH\0SR\0TH\0TW\0US\0VN\0")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8,
- 108u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8,
- 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8,
- 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 76u8, 97u8, 116u8,
- 110u8, 78u8, 107u8, 111u8, 111u8, 77u8, 111u8, 110u8, 103u8, 65u8, 114u8,
- 97u8, 98u8, 65u8, 114u8, 97u8, 98u8, 76u8, 97u8, 116u8, 110u8, 68u8, 101u8,
- 118u8, 97u8, 76u8, 97u8, 116u8, 110u8, 76u8, 97u8, 116u8, 110u8, 76u8,
- 97u8, 116u8, 110u8, 76u8, 97u8, 116u8, 110u8, 65u8, 114u8, 97u8, 98u8,
- 67u8, 121u8, 114u8, 108u8, 67u8, 121u8, 114u8, 108u8, 68u8, 101u8, 118u8,
- 97u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8, 108u8, 72u8, 97u8,
- 110u8, 115u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8,
- 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8,
- 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8,
- 116u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8,
- 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8, 72u8,
- 97u8, 110u8, 116u8, 72u8, 97u8, 110u8, 116u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"ArabArabCyrlArabArabArabArabArabArabArabLatnMongArabArabDevaLatnLatnLatnLatnArabArabCyrlHansHantHantHantHantHantHantHantHantHantHantHantHantHantHantHant")
},
)
},
@@ -286,392 +33,10 @@
#[allow(unused_unsafe)]
::zerovec::ZeroMap::from_parts_unchecked(
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 97u8, 97u8, 0u8, 97u8, 98u8, 0u8, 97u8, 98u8, 114u8, 97u8, 99u8, 101u8,
- 97u8, 99u8, 104u8, 97u8, 100u8, 97u8, 97u8, 100u8, 112u8, 97u8, 100u8,
- 121u8, 97u8, 101u8, 0u8, 97u8, 101u8, 98u8, 97u8, 102u8, 0u8, 97u8, 103u8,
- 113u8, 97u8, 104u8, 111u8, 97u8, 106u8, 116u8, 97u8, 107u8, 0u8, 97u8,
- 107u8, 107u8, 97u8, 108u8, 110u8, 97u8, 108u8, 116u8, 97u8, 109u8, 0u8,
- 97u8, 109u8, 111u8, 97u8, 110u8, 0u8, 97u8, 110u8, 110u8, 97u8, 111u8,
- 122u8, 97u8, 112u8, 100u8, 97u8, 114u8, 0u8, 97u8, 114u8, 99u8, 97u8,
- 114u8, 110u8, 97u8, 114u8, 111u8, 97u8, 114u8, 113u8, 97u8, 114u8, 115u8,
- 97u8, 114u8, 121u8, 97u8, 114u8, 122u8, 97u8, 115u8, 0u8, 97u8, 115u8,
- 97u8, 97u8, 115u8, 101u8, 97u8, 115u8, 116u8, 97u8, 116u8, 106u8, 97u8,
- 118u8, 0u8, 97u8, 119u8, 97u8, 97u8, 121u8, 0u8, 97u8, 122u8, 0u8, 98u8,
- 97u8, 0u8, 98u8, 97u8, 108u8, 98u8, 97u8, 110u8, 98u8, 97u8, 112u8, 98u8,
- 97u8, 114u8, 98u8, 97u8, 115u8, 98u8, 97u8, 120u8, 98u8, 98u8, 99u8, 98u8,
- 98u8, 106u8, 98u8, 99u8, 105u8, 98u8, 101u8, 0u8, 98u8, 101u8, 106u8, 98u8,
- 101u8, 109u8, 98u8, 101u8, 119u8, 98u8, 101u8, 122u8, 98u8, 102u8, 100u8,
- 98u8, 102u8, 113u8, 98u8, 102u8, 116u8, 98u8, 102u8, 121u8, 98u8, 103u8,
- 0u8, 98u8, 103u8, 99u8, 98u8, 103u8, 110u8, 98u8, 103u8, 120u8, 98u8,
- 104u8, 98u8, 98u8, 104u8, 105u8, 98u8, 104u8, 111u8, 98u8, 105u8, 0u8,
- 98u8, 105u8, 107u8, 98u8, 105u8, 110u8, 98u8, 106u8, 106u8, 98u8, 106u8,
- 110u8, 98u8, 106u8, 116u8, 98u8, 107u8, 109u8, 98u8, 107u8, 117u8, 98u8,
- 108u8, 97u8, 98u8, 108u8, 103u8, 98u8, 108u8, 116u8, 98u8, 109u8, 0u8,
- 98u8, 109u8, 113u8, 98u8, 110u8, 0u8, 98u8, 111u8, 0u8, 98u8, 112u8, 121u8,
- 98u8, 113u8, 105u8, 98u8, 113u8, 118u8, 98u8, 114u8, 0u8, 98u8, 114u8,
- 97u8, 98u8, 114u8, 104u8, 98u8, 114u8, 120u8, 98u8, 115u8, 0u8, 98u8,
- 115u8, 113u8, 98u8, 115u8, 115u8, 98u8, 116u8, 111u8, 98u8, 116u8, 118u8,
- 98u8, 117u8, 97u8, 98u8, 117u8, 99u8, 98u8, 117u8, 103u8, 98u8, 117u8,
- 109u8, 98u8, 118u8, 98u8, 98u8, 121u8, 110u8, 98u8, 121u8, 118u8, 98u8,
- 122u8, 101u8, 99u8, 97u8, 0u8, 99u8, 97u8, 100u8, 99u8, 99u8, 104u8, 99u8,
- 99u8, 112u8, 99u8, 101u8, 0u8, 99u8, 101u8, 98u8, 99u8, 103u8, 103u8, 99u8,
- 104u8, 0u8, 99u8, 104u8, 107u8, 99u8, 104u8, 109u8, 99u8, 104u8, 111u8,
- 99u8, 104u8, 112u8, 99u8, 104u8, 114u8, 99u8, 105u8, 99u8, 99u8, 106u8,
- 97u8, 99u8, 106u8, 109u8, 99u8, 107u8, 98u8, 99u8, 108u8, 99u8, 99u8,
- 109u8, 103u8, 99u8, 111u8, 0u8, 99u8, 111u8, 112u8, 99u8, 112u8, 115u8,
- 99u8, 114u8, 0u8, 99u8, 114u8, 103u8, 99u8, 114u8, 104u8, 99u8, 114u8,
- 107u8, 99u8, 114u8, 108u8, 99u8, 114u8, 115u8, 99u8, 115u8, 0u8, 99u8,
- 115u8, 98u8, 99u8, 115u8, 119u8, 99u8, 116u8, 100u8, 99u8, 117u8, 0u8,
- 99u8, 118u8, 0u8, 99u8, 121u8, 0u8, 100u8, 97u8, 0u8, 100u8, 97u8, 102u8,
- 100u8, 97u8, 107u8, 100u8, 97u8, 114u8, 100u8, 97u8, 118u8, 100u8, 99u8,
- 99u8, 100u8, 101u8, 0u8, 100u8, 101u8, 110u8, 100u8, 103u8, 114u8, 100u8,
- 106u8, 101u8, 100u8, 109u8, 102u8, 100u8, 110u8, 106u8, 100u8, 111u8,
- 105u8, 100u8, 114u8, 104u8, 100u8, 115u8, 98u8, 100u8, 116u8, 109u8, 100u8,
- 116u8, 112u8, 100u8, 116u8, 121u8, 100u8, 117u8, 97u8, 100u8, 118u8, 0u8,
- 100u8, 121u8, 111u8, 100u8, 121u8, 117u8, 100u8, 122u8, 0u8, 101u8, 98u8,
- 117u8, 101u8, 101u8, 0u8, 101u8, 102u8, 105u8, 101u8, 103u8, 108u8, 101u8,
- 103u8, 121u8, 101u8, 107u8, 121u8, 101u8, 108u8, 0u8, 101u8, 110u8, 0u8,
- 101u8, 111u8, 0u8, 101u8, 115u8, 0u8, 101u8, 115u8, 103u8, 101u8, 115u8,
- 117u8, 101u8, 116u8, 0u8, 101u8, 116u8, 116u8, 101u8, 117u8, 0u8, 101u8,
- 119u8, 111u8, 101u8, 120u8, 116u8, 102u8, 97u8, 0u8, 102u8, 97u8, 110u8,
- 102u8, 102u8, 0u8, 102u8, 102u8, 109u8, 102u8, 105u8, 0u8, 102u8, 105u8,
- 97u8, 102u8, 105u8, 108u8, 102u8, 105u8, 116u8, 102u8, 106u8, 0u8, 102u8,
- 111u8, 0u8, 102u8, 111u8, 110u8, 102u8, 114u8, 0u8, 102u8, 114u8, 99u8,
- 102u8, 114u8, 112u8, 102u8, 114u8, 114u8, 102u8, 114u8, 115u8, 102u8,
- 117u8, 98u8, 102u8, 117u8, 100u8, 102u8, 117u8, 102u8, 102u8, 117u8, 113u8,
- 102u8, 117u8, 114u8, 102u8, 117u8, 118u8, 102u8, 118u8, 114u8, 102u8,
- 121u8, 0u8, 103u8, 97u8, 0u8, 103u8, 97u8, 97u8, 103u8, 97u8, 103u8, 103u8,
- 97u8, 110u8, 103u8, 97u8, 121u8, 103u8, 98u8, 109u8, 103u8, 98u8, 122u8,
- 103u8, 99u8, 114u8, 103u8, 100u8, 0u8, 103u8, 101u8, 122u8, 103u8, 103u8,
- 110u8, 103u8, 105u8, 108u8, 103u8, 106u8, 107u8, 103u8, 106u8, 117u8,
- 103u8, 108u8, 0u8, 103u8, 108u8, 107u8, 103u8, 110u8, 0u8, 103u8, 111u8,
- 109u8, 103u8, 111u8, 110u8, 103u8, 111u8, 114u8, 103u8, 111u8, 115u8,
- 103u8, 111u8, 116u8, 103u8, 114u8, 99u8, 103u8, 114u8, 116u8, 103u8, 115u8,
- 119u8, 103u8, 117u8, 0u8, 103u8, 117u8, 98u8, 103u8, 117u8, 99u8, 103u8,
- 117u8, 114u8, 103u8, 117u8, 122u8, 103u8, 118u8, 0u8, 103u8, 118u8, 114u8,
- 103u8, 119u8, 105u8, 104u8, 97u8, 0u8, 104u8, 97u8, 107u8, 104u8, 97u8,
- 119u8, 104u8, 97u8, 122u8, 104u8, 101u8, 0u8, 104u8, 105u8, 0u8, 104u8,
- 105u8, 102u8, 104u8, 105u8, 108u8, 104u8, 108u8, 117u8, 104u8, 109u8,
- 100u8, 104u8, 110u8, 100u8, 104u8, 110u8, 101u8, 104u8, 110u8, 106u8,
- 104u8, 110u8, 110u8, 104u8, 110u8, 111u8, 104u8, 111u8, 0u8, 104u8, 111u8,
- 99u8, 104u8, 111u8, 106u8, 104u8, 114u8, 0u8, 104u8, 115u8, 98u8, 104u8,
- 115u8, 110u8, 104u8, 116u8, 0u8, 104u8, 117u8, 0u8, 104u8, 117u8, 114u8,
- 104u8, 121u8, 0u8, 104u8, 122u8, 0u8, 105u8, 97u8, 0u8, 105u8, 98u8, 97u8,
- 105u8, 98u8, 98u8, 105u8, 100u8, 0u8, 105u8, 102u8, 101u8, 105u8, 103u8,
- 0u8, 105u8, 105u8, 0u8, 105u8, 107u8, 0u8, 105u8, 108u8, 111u8, 105u8,
- 110u8, 0u8, 105u8, 110u8, 104u8, 105u8, 111u8, 0u8, 105u8, 115u8, 0u8,
- 105u8, 116u8, 0u8, 105u8, 117u8, 0u8, 105u8, 119u8, 0u8, 105u8, 122u8,
- 104u8, 106u8, 97u8, 0u8, 106u8, 97u8, 109u8, 106u8, 98u8, 111u8, 106u8,
- 103u8, 111u8, 106u8, 105u8, 0u8, 106u8, 109u8, 99u8, 106u8, 109u8, 108u8,
- 106u8, 117u8, 116u8, 106u8, 118u8, 0u8, 106u8, 119u8, 0u8, 107u8, 97u8,
- 0u8, 107u8, 97u8, 97u8, 107u8, 97u8, 98u8, 107u8, 97u8, 99u8, 107u8, 97u8,
- 106u8, 107u8, 97u8, 109u8, 107u8, 97u8, 111u8, 107u8, 97u8, 119u8, 107u8,
- 98u8, 100u8, 107u8, 98u8, 121u8, 107u8, 99u8, 103u8, 107u8, 99u8, 107u8,
- 107u8, 100u8, 101u8, 107u8, 100u8, 104u8, 107u8, 100u8, 116u8, 107u8,
- 101u8, 97u8, 107u8, 101u8, 110u8, 107u8, 102u8, 111u8, 107u8, 102u8, 114u8,
- 107u8, 102u8, 121u8, 107u8, 103u8, 0u8, 107u8, 103u8, 101u8, 107u8, 103u8,
- 112u8, 107u8, 104u8, 97u8, 107u8, 104u8, 98u8, 107u8, 104u8, 110u8, 107u8,
- 104u8, 113u8, 107u8, 104u8, 116u8, 107u8, 104u8, 119u8, 107u8, 105u8, 0u8,
- 107u8, 105u8, 117u8, 107u8, 106u8, 0u8, 107u8, 106u8, 103u8, 107u8, 107u8,
- 0u8, 107u8, 107u8, 106u8, 107u8, 108u8, 0u8, 107u8, 108u8, 110u8, 107u8,
- 109u8, 0u8, 107u8, 109u8, 98u8, 107u8, 110u8, 0u8, 107u8, 110u8, 102u8,
- 107u8, 111u8, 0u8, 107u8, 111u8, 105u8, 107u8, 111u8, 107u8, 107u8, 111u8,
- 115u8, 107u8, 112u8, 101u8, 107u8, 114u8, 99u8, 107u8, 114u8, 105u8, 107u8,
- 114u8, 106u8, 107u8, 114u8, 108u8, 107u8, 114u8, 117u8, 107u8, 115u8, 0u8,
- 107u8, 115u8, 98u8, 107u8, 115u8, 102u8, 107u8, 115u8, 104u8, 107u8, 116u8,
- 114u8, 107u8, 117u8, 0u8, 107u8, 117u8, 109u8, 107u8, 118u8, 0u8, 107u8,
- 118u8, 114u8, 107u8, 118u8, 120u8, 107u8, 119u8, 0u8, 107u8, 119u8, 107u8,
- 107u8, 120u8, 108u8, 107u8, 120u8, 109u8, 107u8, 120u8, 112u8, 107u8,
- 121u8, 0u8, 107u8, 122u8, 106u8, 107u8, 122u8, 116u8, 108u8, 97u8, 0u8,
- 108u8, 97u8, 98u8, 108u8, 97u8, 100u8, 108u8, 97u8, 103u8, 108u8, 97u8,
- 104u8, 108u8, 97u8, 106u8, 108u8, 98u8, 0u8, 108u8, 98u8, 101u8, 108u8,
- 98u8, 119u8, 108u8, 99u8, 112u8, 108u8, 101u8, 112u8, 108u8, 101u8, 122u8,
- 108u8, 103u8, 0u8, 108u8, 105u8, 0u8, 108u8, 105u8, 102u8, 108u8, 105u8,
- 106u8, 108u8, 105u8, 108u8, 108u8, 105u8, 115u8, 108u8, 106u8, 112u8,
- 108u8, 107u8, 105u8, 108u8, 107u8, 116u8, 108u8, 109u8, 110u8, 108u8,
- 109u8, 111u8, 108u8, 110u8, 0u8, 108u8, 111u8, 0u8, 108u8, 111u8, 108u8,
- 108u8, 111u8, 122u8, 108u8, 114u8, 99u8, 108u8, 116u8, 0u8, 108u8, 116u8,
- 103u8, 108u8, 117u8, 0u8, 108u8, 117u8, 97u8, 108u8, 117u8, 111u8, 108u8,
- 117u8, 121u8, 108u8, 117u8, 122u8, 108u8, 118u8, 0u8, 108u8, 119u8, 108u8,
- 108u8, 122u8, 104u8, 108u8, 122u8, 122u8, 109u8, 97u8, 100u8, 109u8, 97u8,
- 102u8, 109u8, 97u8, 103u8, 109u8, 97u8, 105u8, 109u8, 97u8, 107u8, 109u8,
- 97u8, 110u8, 109u8, 97u8, 115u8, 109u8, 97u8, 122u8, 109u8, 100u8, 102u8,
- 109u8, 100u8, 104u8, 109u8, 100u8, 114u8, 109u8, 101u8, 110u8, 109u8,
- 101u8, 114u8, 109u8, 102u8, 97u8, 109u8, 102u8, 101u8, 109u8, 103u8, 0u8,
- 109u8, 103u8, 104u8, 109u8, 103u8, 111u8, 109u8, 103u8, 112u8, 109u8,
- 103u8, 121u8, 109u8, 104u8, 0u8, 109u8, 105u8, 0u8, 109u8, 105u8, 99u8,
- 109u8, 105u8, 110u8, 109u8, 107u8, 0u8, 109u8, 108u8, 0u8, 109u8, 108u8,
- 115u8, 109u8, 110u8, 0u8, 109u8, 110u8, 105u8, 109u8, 110u8, 119u8, 109u8,
- 111u8, 0u8, 109u8, 111u8, 101u8, 109u8, 111u8, 104u8, 109u8, 111u8, 115u8,
- 109u8, 114u8, 0u8, 109u8, 114u8, 100u8, 109u8, 114u8, 106u8, 109u8, 114u8,
- 111u8, 109u8, 115u8, 0u8, 109u8, 116u8, 0u8, 109u8, 116u8, 114u8, 109u8,
- 117u8, 97u8, 109u8, 117u8, 115u8, 109u8, 118u8, 121u8, 109u8, 119u8, 107u8,
- 109u8, 119u8, 114u8, 109u8, 119u8, 118u8, 109u8, 119u8, 119u8, 109u8,
- 120u8, 99u8, 109u8, 121u8, 0u8, 109u8, 121u8, 118u8, 109u8, 121u8, 120u8,
- 109u8, 121u8, 122u8, 109u8, 122u8, 110u8, 110u8, 97u8, 0u8, 110u8, 97u8,
- 110u8, 110u8, 97u8, 112u8, 110u8, 97u8, 113u8, 110u8, 98u8, 0u8, 110u8,
- 99u8, 104u8, 110u8, 100u8, 0u8, 110u8, 100u8, 99u8, 110u8, 100u8, 115u8,
- 110u8, 101u8, 0u8, 110u8, 101u8, 119u8, 110u8, 103u8, 0u8, 110u8, 103u8,
- 108u8, 110u8, 104u8, 101u8, 110u8, 104u8, 119u8, 110u8, 105u8, 106u8,
- 110u8, 105u8, 117u8, 110u8, 106u8, 111u8, 110u8, 108u8, 0u8, 110u8, 109u8,
- 103u8, 110u8, 110u8, 0u8, 110u8, 110u8, 104u8, 110u8, 110u8, 112u8, 110u8,
- 111u8, 0u8, 110u8, 111u8, 100u8, 110u8, 111u8, 101u8, 110u8, 111u8, 110u8,
- 110u8, 113u8, 111u8, 110u8, 114u8, 0u8, 110u8, 115u8, 107u8, 110u8, 115u8,
- 111u8, 110u8, 115u8, 116u8, 110u8, 117u8, 115u8, 110u8, 118u8, 0u8, 110u8,
- 120u8, 113u8, 110u8, 121u8, 0u8, 110u8, 121u8, 109u8, 110u8, 121u8, 110u8,
- 110u8, 122u8, 105u8, 111u8, 99u8, 0u8, 111u8, 106u8, 0u8, 111u8, 106u8,
- 115u8, 111u8, 107u8, 97u8, 111u8, 109u8, 0u8, 111u8, 114u8, 0u8, 111u8,
- 115u8, 0u8, 111u8, 115u8, 97u8, 111u8, 116u8, 107u8, 111u8, 117u8, 105u8,
- 112u8, 97u8, 0u8, 112u8, 97u8, 103u8, 112u8, 97u8, 108u8, 112u8, 97u8,
- 109u8, 112u8, 97u8, 112u8, 112u8, 97u8, 117u8, 112u8, 99u8, 100u8, 112u8,
- 99u8, 109u8, 112u8, 100u8, 99u8, 112u8, 100u8, 116u8, 112u8, 101u8, 111u8,
- 112u8, 102u8, 108u8, 112u8, 104u8, 110u8, 112u8, 105u8, 115u8, 112u8,
- 107u8, 97u8, 112u8, 107u8, 111u8, 112u8, 108u8, 0u8, 112u8, 109u8, 115u8,
- 112u8, 110u8, 116u8, 112u8, 111u8, 110u8, 112u8, 112u8, 97u8, 112u8, 113u8,
- 109u8, 112u8, 114u8, 97u8, 112u8, 114u8, 100u8, 112u8, 114u8, 103u8, 112u8,
- 115u8, 0u8, 112u8, 116u8, 0u8, 112u8, 117u8, 117u8, 113u8, 117u8, 0u8,
- 113u8, 117u8, 99u8, 113u8, 117u8, 103u8, 114u8, 97u8, 106u8, 114u8, 99u8,
- 102u8, 114u8, 101u8, 106u8, 114u8, 103u8, 110u8, 114u8, 104u8, 103u8,
- 114u8, 105u8, 97u8, 114u8, 105u8, 102u8, 114u8, 106u8, 115u8, 114u8, 107u8,
- 116u8, 114u8, 109u8, 0u8, 114u8, 109u8, 102u8, 114u8, 109u8, 111u8, 114u8,
- 109u8, 116u8, 114u8, 109u8, 117u8, 114u8, 110u8, 0u8, 114u8, 110u8, 103u8,
- 114u8, 111u8, 0u8, 114u8, 111u8, 98u8, 114u8, 111u8, 102u8, 114u8, 116u8,
- 109u8, 114u8, 117u8, 0u8, 114u8, 117u8, 101u8, 114u8, 117u8, 103u8, 114u8,
- 119u8, 0u8, 114u8, 119u8, 107u8, 114u8, 121u8, 117u8, 115u8, 97u8, 0u8,
- 115u8, 97u8, 102u8, 115u8, 97u8, 104u8, 115u8, 97u8, 113u8, 115u8, 97u8,
- 115u8, 115u8, 97u8, 116u8, 115u8, 97u8, 118u8, 115u8, 97u8, 122u8, 115u8,
- 98u8, 112u8, 115u8, 99u8, 0u8, 115u8, 99u8, 107u8, 115u8, 99u8, 110u8,
- 115u8, 99u8, 111u8, 115u8, 100u8, 0u8, 115u8, 100u8, 99u8, 115u8, 100u8,
- 104u8, 115u8, 101u8, 0u8, 115u8, 101u8, 102u8, 115u8, 101u8, 104u8, 115u8,
- 101u8, 105u8, 115u8, 101u8, 115u8, 115u8, 103u8, 0u8, 115u8, 103u8, 97u8,
- 115u8, 103u8, 115u8, 115u8, 104u8, 105u8, 115u8, 104u8, 110u8, 115u8,
- 105u8, 0u8, 115u8, 105u8, 100u8, 115u8, 107u8, 0u8, 115u8, 107u8, 114u8,
- 115u8, 108u8, 0u8, 115u8, 108u8, 105u8, 115u8, 108u8, 121u8, 115u8, 109u8,
- 0u8, 115u8, 109u8, 97u8, 115u8, 109u8, 100u8, 115u8, 109u8, 106u8, 115u8,
- 109u8, 110u8, 115u8, 109u8, 112u8, 115u8, 109u8, 115u8, 115u8, 110u8, 0u8,
- 115u8, 110u8, 98u8, 115u8, 110u8, 107u8, 115u8, 111u8, 0u8, 115u8, 111u8,
- 103u8, 115u8, 111u8, 117u8, 115u8, 113u8, 0u8, 115u8, 114u8, 0u8, 115u8,
- 114u8, 98u8, 115u8, 114u8, 110u8, 115u8, 114u8, 114u8, 115u8, 114u8, 120u8,
- 115u8, 115u8, 0u8, 115u8, 115u8, 121u8, 115u8, 116u8, 0u8, 115u8, 116u8,
- 113u8, 115u8, 117u8, 0u8, 115u8, 117u8, 107u8, 115u8, 117u8, 115u8, 115u8,
- 118u8, 0u8, 115u8, 119u8, 0u8, 115u8, 119u8, 98u8, 115u8, 119u8, 99u8,
- 115u8, 119u8, 103u8, 115u8, 119u8, 118u8, 115u8, 120u8, 110u8, 115u8,
- 121u8, 108u8, 115u8, 121u8, 114u8, 115u8, 122u8, 108u8, 116u8, 97u8, 0u8,
- 116u8, 97u8, 106u8, 116u8, 98u8, 119u8, 116u8, 99u8, 121u8, 116u8, 100u8,
- 100u8, 116u8, 100u8, 103u8, 116u8, 100u8, 104u8, 116u8, 100u8, 117u8,
- 116u8, 101u8, 0u8, 116u8, 101u8, 109u8, 116u8, 101u8, 111u8, 116u8, 101u8,
- 116u8, 116u8, 103u8, 0u8, 116u8, 104u8, 0u8, 116u8, 104u8, 108u8, 116u8,
- 104u8, 113u8, 116u8, 104u8, 114u8, 116u8, 105u8, 0u8, 116u8, 105u8, 103u8,
- 116u8, 105u8, 118u8, 116u8, 107u8, 0u8, 116u8, 107u8, 108u8, 116u8, 107u8,
- 114u8, 116u8, 107u8, 116u8, 116u8, 108u8, 0u8, 116u8, 108u8, 121u8, 116u8,
- 109u8, 104u8, 116u8, 110u8, 0u8, 116u8, 111u8, 0u8, 116u8, 111u8, 103u8,
- 116u8, 111u8, 107u8, 116u8, 112u8, 105u8, 116u8, 114u8, 0u8, 116u8, 114u8,
- 117u8, 116u8, 114u8, 118u8, 116u8, 114u8, 119u8, 116u8, 115u8, 0u8, 116u8,
- 115u8, 100u8, 116u8, 115u8, 102u8, 116u8, 115u8, 103u8, 116u8, 115u8,
- 106u8, 116u8, 116u8, 0u8, 116u8, 116u8, 106u8, 116u8, 116u8, 115u8, 116u8,
- 116u8, 116u8, 116u8, 117u8, 109u8, 116u8, 118u8, 108u8, 116u8, 119u8,
- 113u8, 116u8, 120u8, 103u8, 116u8, 120u8, 111u8, 116u8, 121u8, 0u8, 116u8,
- 121u8, 118u8, 116u8, 122u8, 109u8, 117u8, 100u8, 105u8, 117u8, 100u8,
- 109u8, 117u8, 103u8, 0u8, 117u8, 103u8, 97u8, 117u8, 107u8, 0u8, 117u8,
- 108u8, 105u8, 117u8, 109u8, 98u8, 117u8, 110u8, 114u8, 117u8, 110u8, 120u8,
- 117u8, 114u8, 0u8, 117u8, 122u8, 0u8, 118u8, 97u8, 105u8, 118u8, 101u8,
- 0u8, 118u8, 101u8, 99u8, 118u8, 101u8, 112u8, 118u8, 105u8, 0u8, 118u8,
- 105u8, 99u8, 118u8, 108u8, 115u8, 118u8, 109u8, 102u8, 118u8, 109u8, 119u8,
- 118u8, 111u8, 0u8, 118u8, 111u8, 116u8, 118u8, 114u8, 111u8, 118u8, 117u8,
- 110u8, 119u8, 97u8, 0u8, 119u8, 97u8, 101u8, 119u8, 97u8, 108u8, 119u8,
- 97u8, 114u8, 119u8, 98u8, 112u8, 119u8, 98u8, 113u8, 119u8, 98u8, 114u8,
- 119u8, 108u8, 115u8, 119u8, 110u8, 105u8, 119u8, 111u8, 0u8, 119u8, 115u8,
- 103u8, 119u8, 116u8, 109u8, 119u8, 117u8, 117u8, 120u8, 97u8, 118u8, 120u8,
- 99u8, 111u8, 120u8, 99u8, 114u8, 120u8, 104u8, 0u8, 120u8, 108u8, 99u8,
- 120u8, 108u8, 100u8, 120u8, 109u8, 102u8, 120u8, 109u8, 110u8, 120u8,
- 109u8, 114u8, 120u8, 110u8, 97u8, 120u8, 110u8, 114u8, 120u8, 111u8, 103u8,
- 120u8, 112u8, 114u8, 120u8, 115u8, 97u8, 120u8, 115u8, 114u8, 121u8, 97u8,
- 111u8, 121u8, 97u8, 112u8, 121u8, 97u8, 118u8, 121u8, 98u8, 98u8, 121u8,
- 105u8, 0u8, 121u8, 111u8, 0u8, 121u8, 114u8, 108u8, 121u8, 117u8, 97u8,
- 121u8, 117u8, 101u8, 122u8, 97u8, 0u8, 122u8, 97u8, 103u8, 122u8, 100u8,
- 106u8, 122u8, 101u8, 97u8, 122u8, 103u8, 104u8, 122u8, 104u8, 0u8, 122u8,
- 104u8, 120u8, 122u8, 107u8, 116u8, 122u8, 108u8, 109u8, 122u8, 109u8,
- 105u8, 122u8, 117u8, 0u8, 122u8, 122u8, 97u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"af\0am\0ar\0as\0astaz\0be\0bg\0bgcbhobn\0br\0brxbs\0ca\0cebchrcs\0cv\0cy\0da\0de\0doidsbel\0en\0es\0et\0eu\0fa\0ff\0fi\0filfo\0fr\0ga\0gd\0gl\0gu\0ha\0he\0hi\0hr\0hsbhu\0hy\0ia\0id\0ig\0is\0it\0ja\0jv\0ka\0keakgpkk\0km\0kn\0ko\0kokks\0ky\0lo\0lt\0lv\0maimi\0mk\0ml\0mn\0mnimr\0ms\0my\0ne\0nl\0nn\0no\0or\0pa\0pcmpl\0ps\0pt\0qu\0rajrm\0ro\0ru\0sa\0satsc\0sd\0si\0sk\0sl\0so\0sq\0sr\0su\0sv\0sw\0ta\0te\0tg\0th\0ti\0tk\0to\0tr\0tt\0uk\0ur\0uz\0vi\0wo\0xh\0yo\0yrlyuezh\0zu\0")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 69u8, 84u8, 0u8, 71u8, 69u8, 0u8, 71u8, 72u8, 0u8, 73u8, 68u8, 0u8, 85u8,
- 71u8, 0u8, 71u8, 72u8, 0u8, 66u8, 84u8, 0u8, 82u8, 85u8, 0u8, 73u8, 82u8,
- 0u8, 84u8, 78u8, 0u8, 90u8, 65u8, 0u8, 67u8, 77u8, 0u8, 73u8, 78u8, 0u8,
- 84u8, 78u8, 0u8, 71u8, 72u8, 0u8, 73u8, 81u8, 0u8, 88u8, 75u8, 0u8, 82u8,
- 85u8, 0u8, 69u8, 84u8, 0u8, 78u8, 71u8, 0u8, 69u8, 83u8, 0u8, 78u8, 71u8,
- 0u8, 73u8, 68u8, 0u8, 84u8, 71u8, 0u8, 69u8, 71u8, 0u8, 73u8, 82u8, 0u8,
- 67u8, 76u8, 0u8, 66u8, 79u8, 0u8, 68u8, 90u8, 0u8, 83u8, 65u8, 0u8, 77u8,
- 65u8, 0u8, 69u8, 71u8, 0u8, 73u8, 78u8, 0u8, 84u8, 90u8, 0u8, 85u8, 83u8,
- 0u8, 69u8, 83u8, 0u8, 67u8, 65u8, 0u8, 82u8, 85u8, 0u8, 73u8, 78u8, 0u8,
- 66u8, 79u8, 0u8, 65u8, 90u8, 0u8, 82u8, 85u8, 0u8, 80u8, 75u8, 0u8, 73u8,
- 68u8, 0u8, 78u8, 80u8, 0u8, 65u8, 84u8, 0u8, 67u8, 77u8, 0u8, 67u8, 77u8,
- 0u8, 73u8, 68u8, 0u8, 67u8, 77u8, 0u8, 67u8, 73u8, 0u8, 66u8, 89u8, 0u8,
- 83u8, 68u8, 0u8, 90u8, 77u8, 0u8, 73u8, 68u8, 0u8, 84u8, 90u8, 0u8, 67u8,
- 77u8, 0u8, 73u8, 78u8, 0u8, 80u8, 75u8, 0u8, 73u8, 78u8, 0u8, 66u8, 71u8,
- 0u8, 73u8, 78u8, 0u8, 80u8, 75u8, 0u8, 84u8, 82u8, 0u8, 73u8, 78u8, 0u8,
- 73u8, 78u8, 0u8, 73u8, 78u8, 0u8, 86u8, 85u8, 0u8, 80u8, 72u8, 0u8, 78u8,
- 71u8, 0u8, 73u8, 78u8, 0u8, 73u8, 68u8, 0u8, 83u8, 78u8, 0u8, 67u8, 77u8,
- 0u8, 80u8, 72u8, 0u8, 67u8, 65u8, 0u8, 77u8, 89u8, 0u8, 86u8, 78u8, 0u8,
- 77u8, 76u8, 0u8, 77u8, 76u8, 0u8, 66u8, 68u8, 0u8, 67u8, 78u8, 0u8, 73u8,
- 78u8, 0u8, 73u8, 82u8, 0u8, 67u8, 73u8, 0u8, 70u8, 82u8, 0u8, 73u8, 78u8,
- 0u8, 80u8, 75u8, 0u8, 73u8, 78u8, 0u8, 66u8, 65u8, 0u8, 76u8, 82u8, 0u8,
- 67u8, 77u8, 0u8, 80u8, 72u8, 0u8, 80u8, 75u8, 0u8, 82u8, 85u8, 0u8, 89u8,
- 84u8, 0u8, 73u8, 68u8, 0u8, 67u8, 77u8, 0u8, 71u8, 81u8, 0u8, 69u8, 82u8,
- 0u8, 67u8, 77u8, 0u8, 77u8, 76u8, 0u8, 69u8, 83u8, 0u8, 85u8, 83u8, 0u8,
- 78u8, 71u8, 0u8, 66u8, 68u8, 0u8, 82u8, 85u8, 0u8, 80u8, 72u8, 0u8, 85u8,
- 71u8, 0u8, 71u8, 85u8, 0u8, 70u8, 77u8, 0u8, 82u8, 85u8, 0u8, 85u8, 83u8,
- 0u8, 67u8, 65u8, 0u8, 85u8, 83u8, 0u8, 85u8, 83u8, 0u8, 75u8, 72u8, 0u8,
- 86u8, 78u8, 0u8, 73u8, 81u8, 0u8, 67u8, 65u8, 0u8, 77u8, 78u8, 0u8, 70u8,
- 82u8, 0u8, 69u8, 71u8, 0u8, 80u8, 72u8, 0u8, 67u8, 65u8, 0u8, 67u8, 65u8,
- 0u8, 85u8, 65u8, 0u8, 67u8, 65u8, 0u8, 67u8, 65u8, 0u8, 83u8, 67u8, 0u8,
- 67u8, 90u8, 0u8, 80u8, 76u8, 0u8, 67u8, 65u8, 0u8, 77u8, 77u8, 0u8, 82u8,
- 85u8, 0u8, 82u8, 85u8, 0u8, 71u8, 66u8, 0u8, 68u8, 75u8, 0u8, 67u8, 73u8,
- 0u8, 85u8, 83u8, 0u8, 82u8, 85u8, 0u8, 75u8, 69u8, 0u8, 73u8, 78u8, 0u8,
- 68u8, 69u8, 0u8, 67u8, 65u8, 0u8, 67u8, 65u8, 0u8, 78u8, 69u8, 0u8, 78u8,
- 71u8, 0u8, 67u8, 73u8, 0u8, 73u8, 78u8, 0u8, 67u8, 78u8, 0u8, 68u8, 69u8,
- 0u8, 77u8, 76u8, 0u8, 77u8, 89u8, 0u8, 78u8, 80u8, 0u8, 67u8, 77u8, 0u8,
- 77u8, 86u8, 0u8, 83u8, 78u8, 0u8, 66u8, 70u8, 0u8, 66u8, 84u8, 0u8, 75u8,
- 69u8, 0u8, 71u8, 72u8, 0u8, 78u8, 71u8, 0u8, 73u8, 84u8, 0u8, 69u8, 71u8,
- 0u8, 77u8, 77u8, 0u8, 71u8, 82u8, 0u8, 85u8, 83u8, 0u8, 48u8, 48u8, 49u8,
- 69u8, 83u8, 0u8, 73u8, 78u8, 0u8, 85u8, 83u8, 0u8, 69u8, 69u8, 0u8, 73u8,
- 84u8, 0u8, 69u8, 83u8, 0u8, 67u8, 77u8, 0u8, 69u8, 83u8, 0u8, 73u8, 82u8,
- 0u8, 71u8, 81u8, 0u8, 83u8, 78u8, 0u8, 77u8, 76u8, 0u8, 70u8, 73u8, 0u8,
- 83u8, 68u8, 0u8, 80u8, 72u8, 0u8, 83u8, 69u8, 0u8, 70u8, 74u8, 0u8, 70u8,
- 79u8, 0u8, 66u8, 74u8, 0u8, 70u8, 82u8, 0u8, 85u8, 83u8, 0u8, 70u8, 82u8,
- 0u8, 68u8, 69u8, 0u8, 68u8, 69u8, 0u8, 67u8, 77u8, 0u8, 87u8, 70u8, 0u8,
- 71u8, 78u8, 0u8, 78u8, 69u8, 0u8, 73u8, 84u8, 0u8, 78u8, 71u8, 0u8, 83u8,
- 68u8, 0u8, 78u8, 76u8, 0u8, 73u8, 69u8, 0u8, 71u8, 72u8, 0u8, 77u8, 68u8,
- 0u8, 67u8, 78u8, 0u8, 73u8, 68u8, 0u8, 73u8, 78u8, 0u8, 73u8, 82u8, 0u8,
- 71u8, 70u8, 0u8, 71u8, 66u8, 0u8, 69u8, 84u8, 0u8, 78u8, 80u8, 0u8, 75u8,
- 73u8, 0u8, 80u8, 75u8, 0u8, 80u8, 75u8, 0u8, 69u8, 83u8, 0u8, 73u8, 82u8,
- 0u8, 80u8, 89u8, 0u8, 73u8, 78u8, 0u8, 73u8, 78u8, 0u8, 73u8, 68u8, 0u8,
- 78u8, 76u8, 0u8, 85u8, 65u8, 0u8, 67u8, 89u8, 0u8, 73u8, 78u8, 0u8, 67u8,
- 72u8, 0u8, 73u8, 78u8, 0u8, 66u8, 82u8, 0u8, 67u8, 79u8, 0u8, 71u8, 72u8,
- 0u8, 75u8, 69u8, 0u8, 73u8, 77u8, 0u8, 78u8, 80u8, 0u8, 67u8, 65u8, 0u8,
- 78u8, 71u8, 0u8, 67u8, 78u8, 0u8, 85u8, 83u8, 0u8, 65u8, 70u8, 0u8, 73u8,
- 76u8, 0u8, 73u8, 78u8, 0u8, 70u8, 74u8, 0u8, 80u8, 72u8, 0u8, 84u8, 82u8,
- 0u8, 67u8, 78u8, 0u8, 80u8, 75u8, 0u8, 73u8, 78u8, 0u8, 85u8, 83u8, 0u8,
- 80u8, 72u8, 0u8, 80u8, 75u8, 0u8, 80u8, 71u8, 0u8, 73u8, 78u8, 0u8, 73u8,
- 78u8, 0u8, 72u8, 82u8, 0u8, 68u8, 69u8, 0u8, 67u8, 78u8, 0u8, 72u8, 84u8,
- 0u8, 72u8, 85u8, 0u8, 67u8, 65u8, 0u8, 65u8, 77u8, 0u8, 78u8, 65u8, 0u8,
- 48u8, 48u8, 49u8, 77u8, 89u8, 0u8, 78u8, 71u8, 0u8, 73u8, 68u8, 0u8, 84u8,
- 71u8, 0u8, 78u8, 71u8, 0u8, 67u8, 78u8, 0u8, 85u8, 83u8, 0u8, 80u8, 72u8,
- 0u8, 73u8, 68u8, 0u8, 82u8, 85u8, 0u8, 48u8, 48u8, 49u8, 73u8, 83u8, 0u8,
- 73u8, 84u8, 0u8, 67u8, 65u8, 0u8, 73u8, 76u8, 0u8, 82u8, 85u8, 0u8, 74u8,
- 80u8, 0u8, 74u8, 77u8, 0u8, 48u8, 48u8, 49u8, 67u8, 77u8, 0u8, 85u8, 65u8,
- 0u8, 84u8, 90u8, 0u8, 78u8, 80u8, 0u8, 68u8, 75u8, 0u8, 73u8, 68u8, 0u8,
- 73u8, 68u8, 0u8, 71u8, 69u8, 0u8, 85u8, 90u8, 0u8, 68u8, 90u8, 0u8, 77u8,
- 77u8, 0u8, 78u8, 71u8, 0u8, 75u8, 69u8, 0u8, 77u8, 76u8, 0u8, 73u8, 68u8,
- 0u8, 82u8, 85u8, 0u8, 78u8, 69u8, 0u8, 78u8, 71u8, 0u8, 90u8, 87u8, 0u8,
- 84u8, 90u8, 0u8, 84u8, 71u8, 0u8, 84u8, 72u8, 0u8, 67u8, 86u8, 0u8, 67u8,
- 77u8, 0u8, 67u8, 73u8, 0u8, 73u8, 78u8, 0u8, 73u8, 78u8, 0u8, 67u8, 68u8,
- 0u8, 73u8, 68u8, 0u8, 66u8, 82u8, 0u8, 73u8, 78u8, 0u8, 67u8, 78u8, 0u8,
- 73u8, 78u8, 0u8, 77u8, 76u8, 0u8, 73u8, 78u8, 0u8, 80u8, 75u8, 0u8, 75u8,
- 69u8, 0u8, 84u8, 82u8, 0u8, 78u8, 65u8, 0u8, 76u8, 65u8, 0u8, 75u8, 90u8,
- 0u8, 67u8, 77u8, 0u8, 71u8, 76u8, 0u8, 75u8, 69u8, 0u8, 75u8, 72u8, 0u8,
- 65u8, 79u8, 0u8, 73u8, 78u8, 0u8, 71u8, 87u8, 0u8, 75u8, 82u8, 0u8, 82u8,
- 85u8, 0u8, 73u8, 78u8, 0u8, 70u8, 77u8, 0u8, 76u8, 82u8, 0u8, 82u8, 85u8,
- 0u8, 83u8, 76u8, 0u8, 80u8, 72u8, 0u8, 82u8, 85u8, 0u8, 73u8, 78u8, 0u8,
- 73u8, 78u8, 0u8, 84u8, 90u8, 0u8, 67u8, 77u8, 0u8, 68u8, 69u8, 0u8, 77u8,
- 89u8, 0u8, 84u8, 82u8, 0u8, 82u8, 85u8, 0u8, 82u8, 85u8, 0u8, 73u8, 68u8,
- 0u8, 80u8, 75u8, 0u8, 71u8, 66u8, 0u8, 67u8, 65u8, 0u8, 73u8, 78u8, 0u8,
- 84u8, 72u8, 0u8, 80u8, 75u8, 0u8, 75u8, 71u8, 0u8, 77u8, 89u8, 0u8, 77u8,
- 89u8, 0u8, 86u8, 65u8, 0u8, 71u8, 82u8, 0u8, 73u8, 76u8, 0u8, 84u8, 90u8,
- 0u8, 80u8, 75u8, 0u8, 85u8, 71u8, 0u8, 76u8, 85u8, 0u8, 82u8, 85u8, 0u8,
- 73u8, 68u8, 0u8, 67u8, 78u8, 0u8, 73u8, 78u8, 0u8, 82u8, 85u8, 0u8, 85u8,
- 71u8, 0u8, 78u8, 76u8, 0u8, 78u8, 80u8, 0u8, 73u8, 84u8, 0u8, 67u8, 65u8,
- 0u8, 67u8, 78u8, 0u8, 73u8, 68u8, 0u8, 73u8, 82u8, 0u8, 85u8, 83u8, 0u8,
- 73u8, 78u8, 0u8, 73u8, 84u8, 0u8, 67u8, 68u8, 0u8, 76u8, 65u8, 0u8, 67u8,
- 68u8, 0u8, 90u8, 77u8, 0u8, 73u8, 82u8, 0u8, 76u8, 84u8, 0u8, 76u8, 86u8,
- 0u8, 67u8, 68u8, 0u8, 67u8, 68u8, 0u8, 75u8, 69u8, 0u8, 75u8, 69u8, 0u8,
- 73u8, 82u8, 0u8, 76u8, 86u8, 0u8, 84u8, 72u8, 0u8, 67u8, 78u8, 0u8, 84u8,
- 82u8, 0u8, 73u8, 68u8, 0u8, 67u8, 77u8, 0u8, 73u8, 78u8, 0u8, 73u8, 78u8,
- 0u8, 73u8, 68u8, 0u8, 71u8, 77u8, 0u8, 75u8, 69u8, 0u8, 77u8, 88u8, 0u8,
- 82u8, 85u8, 0u8, 80u8, 72u8, 0u8, 73u8, 68u8, 0u8, 83u8, 76u8, 0u8, 75u8,
- 69u8, 0u8, 84u8, 72u8, 0u8, 77u8, 85u8, 0u8, 77u8, 71u8, 0u8, 77u8, 90u8,
- 0u8, 67u8, 77u8, 0u8, 78u8, 80u8, 0u8, 84u8, 90u8, 0u8, 77u8, 72u8, 0u8,
- 78u8, 90u8, 0u8, 67u8, 65u8, 0u8, 73u8, 68u8, 0u8, 77u8, 75u8, 0u8, 73u8,
- 78u8, 0u8, 83u8, 68u8, 0u8, 77u8, 78u8, 0u8, 73u8, 78u8, 0u8, 77u8, 77u8,
- 0u8, 82u8, 79u8, 0u8, 67u8, 65u8, 0u8, 67u8, 65u8, 0u8, 66u8, 70u8, 0u8,
- 73u8, 78u8, 0u8, 78u8, 80u8, 0u8, 82u8, 85u8, 0u8, 66u8, 68u8, 0u8, 77u8,
- 89u8, 0u8, 77u8, 84u8, 0u8, 73u8, 78u8, 0u8, 67u8, 77u8, 0u8, 85u8, 83u8,
- 0u8, 80u8, 75u8, 0u8, 77u8, 76u8, 0u8, 73u8, 78u8, 0u8, 73u8, 68u8, 0u8,
- 85u8, 83u8, 0u8, 90u8, 87u8, 0u8, 77u8, 77u8, 0u8, 82u8, 85u8, 0u8, 85u8,
- 71u8, 0u8, 73u8, 82u8, 0u8, 73u8, 82u8, 0u8, 78u8, 82u8, 0u8, 67u8, 78u8,
- 0u8, 73u8, 84u8, 0u8, 78u8, 65u8, 0u8, 78u8, 79u8, 0u8, 77u8, 88u8, 0u8,
- 90u8, 87u8, 0u8, 77u8, 90u8, 0u8, 68u8, 69u8, 0u8, 78u8, 80u8, 0u8, 78u8,
- 80u8, 0u8, 78u8, 65u8, 0u8, 77u8, 90u8, 0u8, 77u8, 88u8, 0u8, 77u8, 88u8,
- 0u8, 73u8, 68u8, 0u8, 78u8, 85u8, 0u8, 73u8, 78u8, 0u8, 78u8, 76u8, 0u8,
- 67u8, 77u8, 0u8, 78u8, 79u8, 0u8, 67u8, 77u8, 0u8, 73u8, 78u8, 0u8, 78u8,
- 79u8, 0u8, 84u8, 72u8, 0u8, 73u8, 78u8, 0u8, 83u8, 69u8, 0u8, 71u8, 78u8,
- 0u8, 90u8, 65u8, 0u8, 67u8, 65u8, 0u8, 90u8, 65u8, 0u8, 73u8, 78u8, 0u8,
- 83u8, 83u8, 0u8, 85u8, 83u8, 0u8, 67u8, 78u8, 0u8, 77u8, 87u8, 0u8, 84u8,
- 90u8, 0u8, 85u8, 71u8, 0u8, 71u8, 72u8, 0u8, 70u8, 82u8, 0u8, 67u8, 65u8,
- 0u8, 67u8, 65u8, 0u8, 67u8, 65u8, 0u8, 69u8, 84u8, 0u8, 73u8, 78u8, 0u8,
- 71u8, 69u8, 0u8, 85u8, 83u8, 0u8, 77u8, 78u8, 0u8, 49u8, 52u8, 51u8, 73u8,
- 78u8, 0u8, 80u8, 72u8, 0u8, 73u8, 82u8, 0u8, 80u8, 72u8, 0u8, 65u8, 87u8,
- 0u8, 80u8, 87u8, 0u8, 70u8, 82u8, 0u8, 78u8, 71u8, 0u8, 85u8, 83u8, 0u8,
- 67u8, 65u8, 0u8, 73u8, 82u8, 0u8, 68u8, 69u8, 0u8, 76u8, 66u8, 0u8, 83u8,
- 66u8, 0u8, 73u8, 78u8, 0u8, 75u8, 69u8, 0u8, 80u8, 76u8, 0u8, 73u8, 84u8,
- 0u8, 71u8, 82u8, 0u8, 70u8, 77u8, 0u8, 73u8, 78u8, 0u8, 67u8, 65u8, 0u8,
- 80u8, 75u8, 0u8, 73u8, 82u8, 0u8, 48u8, 48u8, 49u8, 65u8, 70u8, 0u8, 66u8,
- 82u8, 0u8, 71u8, 65u8, 0u8, 80u8, 69u8, 0u8, 71u8, 84u8, 0u8, 69u8, 67u8,
- 0u8, 73u8, 78u8, 0u8, 82u8, 69u8, 0u8, 73u8, 68u8, 0u8, 73u8, 84u8, 0u8,
- 77u8, 77u8, 0u8, 73u8, 78u8, 0u8, 77u8, 65u8, 0u8, 78u8, 80u8, 0u8, 66u8,
- 68u8, 0u8, 67u8, 72u8, 0u8, 70u8, 73u8, 0u8, 67u8, 72u8, 0u8, 73u8, 82u8,
- 0u8, 83u8, 69u8, 0u8, 66u8, 73u8, 0u8, 77u8, 90u8, 0u8, 82u8, 79u8, 0u8,
- 73u8, 68u8, 0u8, 84u8, 90u8, 0u8, 70u8, 74u8, 0u8, 82u8, 85u8, 0u8, 85u8,
- 65u8, 0u8, 83u8, 66u8, 0u8, 82u8, 87u8, 0u8, 84u8, 90u8, 0u8, 74u8, 80u8,
- 0u8, 73u8, 78u8, 0u8, 71u8, 72u8, 0u8, 82u8, 85u8, 0u8, 75u8, 69u8, 0u8,
- 73u8, 68u8, 0u8, 73u8, 78u8, 0u8, 83u8, 78u8, 0u8, 73u8, 78u8, 0u8, 84u8,
- 90u8, 0u8, 73u8, 84u8, 0u8, 73u8, 78u8, 0u8, 73u8, 84u8, 0u8, 71u8, 66u8,
- 0u8, 80u8, 75u8, 0u8, 73u8, 84u8, 0u8, 73u8, 82u8, 0u8, 78u8, 79u8, 0u8,
- 67u8, 73u8, 0u8, 77u8, 90u8, 0u8, 77u8, 88u8, 0u8, 77u8, 76u8, 0u8, 67u8,
- 70u8, 0u8, 73u8, 69u8, 0u8, 76u8, 84u8, 0u8, 77u8, 65u8, 0u8, 77u8, 77u8,
- 0u8, 76u8, 75u8, 0u8, 69u8, 84u8, 0u8, 83u8, 75u8, 0u8, 80u8, 75u8, 0u8,
- 83u8, 73u8, 0u8, 80u8, 76u8, 0u8, 73u8, 68u8, 0u8, 87u8, 83u8, 0u8, 83u8,
- 69u8, 0u8, 65u8, 79u8, 0u8, 83u8, 69u8, 0u8, 70u8, 73u8, 0u8, 73u8, 76u8,
- 0u8, 70u8, 73u8, 0u8, 90u8, 87u8, 0u8, 77u8, 89u8, 0u8, 77u8, 76u8, 0u8,
- 83u8, 79u8, 0u8, 85u8, 90u8, 0u8, 84u8, 72u8, 0u8, 65u8, 76u8, 0u8, 82u8,
- 83u8, 0u8, 73u8, 78u8, 0u8, 83u8, 82u8, 0u8, 83u8, 78u8, 0u8, 73u8, 78u8,
- 0u8, 90u8, 65u8, 0u8, 69u8, 82u8, 0u8, 90u8, 65u8, 0u8, 68u8, 69u8, 0u8,
- 73u8, 68u8, 0u8, 84u8, 90u8, 0u8, 71u8, 78u8, 0u8, 83u8, 69u8, 0u8, 84u8,
- 90u8, 0u8, 89u8, 84u8, 0u8, 67u8, 68u8, 0u8, 68u8, 69u8, 0u8, 73u8, 78u8,
- 0u8, 73u8, 68u8, 0u8, 66u8, 68u8, 0u8, 73u8, 81u8, 0u8, 80u8, 76u8, 0u8,
- 73u8, 78u8, 0u8, 78u8, 80u8, 0u8, 80u8, 72u8, 0u8, 73u8, 78u8, 0u8, 67u8,
- 78u8, 0u8, 78u8, 80u8, 0u8, 78u8, 80u8, 0u8, 77u8, 89u8, 0u8, 73u8, 78u8,
- 0u8, 83u8, 76u8, 0u8, 85u8, 71u8, 0u8, 84u8, 76u8, 0u8, 84u8, 74u8, 0u8,
- 84u8, 72u8, 0u8, 78u8, 80u8, 0u8, 78u8, 80u8, 0u8, 78u8, 80u8, 0u8, 69u8,
- 84u8, 0u8, 69u8, 82u8, 0u8, 78u8, 71u8, 0u8, 84u8, 77u8, 0u8, 84u8, 75u8,
- 0u8, 65u8, 90u8, 0u8, 78u8, 80u8, 0u8, 80u8, 72u8, 0u8, 65u8, 90u8, 0u8,
- 78u8, 69u8, 0u8, 90u8, 65u8, 0u8, 84u8, 79u8, 0u8, 77u8, 87u8, 0u8, 48u8,
- 48u8, 49u8, 80u8, 71u8, 0u8, 84u8, 82u8, 0u8, 84u8, 82u8, 0u8, 84u8, 87u8,
- 0u8, 80u8, 75u8, 0u8, 90u8, 65u8, 0u8, 71u8, 82u8, 0u8, 78u8, 80u8, 0u8,
- 80u8, 72u8, 0u8, 66u8, 84u8, 0u8, 82u8, 85u8, 0u8, 85u8, 71u8, 0u8, 84u8,
- 72u8, 0u8, 65u8, 90u8, 0u8, 77u8, 87u8, 0u8, 84u8, 86u8, 0u8, 78u8, 69u8,
- 0u8, 67u8, 78u8, 0u8, 73u8, 78u8, 0u8, 80u8, 70u8, 0u8, 82u8, 85u8, 0u8,
- 77u8, 65u8, 0u8, 82u8, 85u8, 0u8, 82u8, 85u8, 0u8, 67u8, 78u8, 0u8, 83u8,
- 89u8, 0u8, 85u8, 65u8, 0u8, 70u8, 77u8, 0u8, 65u8, 79u8, 0u8, 73u8, 78u8,
- 0u8, 73u8, 78u8, 0u8, 80u8, 75u8, 0u8, 85u8, 90u8, 0u8, 76u8, 82u8, 0u8,
- 90u8, 65u8, 0u8, 73u8, 84u8, 0u8, 82u8, 85u8, 0u8, 86u8, 78u8, 0u8, 83u8,
- 88u8, 0u8, 66u8, 69u8, 0u8, 68u8, 69u8, 0u8, 77u8, 90u8, 0u8, 48u8, 48u8,
- 49u8, 82u8, 85u8, 0u8, 69u8, 69u8, 0u8, 84u8, 90u8, 0u8, 66u8, 69u8, 0u8,
- 67u8, 72u8, 0u8, 69u8, 84u8, 0u8, 80u8, 72u8, 0u8, 65u8, 85u8, 0u8, 73u8,
- 78u8, 0u8, 73u8, 78u8, 0u8, 87u8, 70u8, 0u8, 75u8, 77u8, 0u8, 83u8, 78u8,
- 0u8, 73u8, 78u8, 0u8, 73u8, 78u8, 0u8, 67u8, 78u8, 0u8, 66u8, 82u8, 0u8,
- 85u8, 90u8, 0u8, 84u8, 82u8, 0u8, 90u8, 65u8, 0u8, 84u8, 82u8, 0u8, 84u8,
- 82u8, 0u8, 71u8, 69u8, 0u8, 67u8, 78u8, 0u8, 83u8, 68u8, 0u8, 83u8, 65u8,
- 0u8, 73u8, 78u8, 0u8, 85u8, 71u8, 0u8, 73u8, 82u8, 0u8, 89u8, 69u8, 0u8,
- 78u8, 80u8, 0u8, 77u8, 90u8, 0u8, 70u8, 77u8, 0u8, 67u8, 77u8, 0u8, 67u8,
- 77u8, 0u8, 48u8, 48u8, 49u8, 78u8, 71u8, 0u8, 66u8, 82u8, 0u8, 77u8, 88u8,
- 0u8, 72u8, 75u8, 0u8, 67u8, 78u8, 0u8, 83u8, 68u8, 0u8, 75u8, 77u8, 0u8,
- 78u8, 76u8, 0u8, 77u8, 65u8, 0u8, 67u8, 78u8, 0u8, 67u8, 78u8, 0u8, 67u8,
- 78u8, 0u8, 84u8, 71u8, 0u8, 77u8, 89u8, 0u8, 90u8, 65u8, 0u8, 84u8, 82u8,
- 0u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"ZA\0ET\0EG\0IN\0ES\0AZ\0BY\0BG\0IN\0IN\0BD\0FR\0IN\0BA\0ES\0PH\0US\0CZ\0RU\0GB\0DK\0DE\0IN\0DE\0GR\0US\0ES\0EE\0ES\0IR\0SN\0FI\0PH\0FO\0FR\0IE\0GB\0ES\0IN\0NG\0IL\0IN\0HR\0DE\0HU\0AM\x00001ID\0NG\0IS\0IT\0JP\0ID\0GE\0CV\0BR\0KZ\0KH\0IN\0KR\0IN\0IN\0KG\0LA\0LT\0LV\0IN\0NZ\0MK\0IN\0MN\0IN\0IN\0MY\0MM\0NP\0NL\0NO\0NO\0IN\0IN\0NG\0PL\0AF\0BR\0PE\0IN\0CH\0RO\0RU\0IN\0IN\0IT\0PK\0LK\0SK\0SI\0SO\0AL\0RS\0ID\0SE\0TZ\0IN\0IN\0TJ\0TH\0ET\0TM\0TO\0TR\0RU\0UA\0PK\0UZ\0VN\0SN\0ZA\0NG\0BR\0HK\0CN\0ZA\0")
},
)
},
@@ -679,49 +44,22 @@
#[allow(unused_unsafe)]
::zerovec::ZeroMap2d::from_parts_unchecked(
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 97u8, 114u8, 99u8, 97u8, 122u8, 0u8, 99u8, 117u8, 0u8, 101u8, 110u8, 0u8,
- 102u8, 102u8, 0u8, 103u8, 114u8, 99u8, 107u8, 107u8, 0u8, 107u8, 117u8,
- 0u8, 107u8, 121u8, 0u8, 108u8, 105u8, 102u8, 109u8, 97u8, 110u8, 109u8,
- 110u8, 0u8, 112u8, 97u8, 0u8, 112u8, 97u8, 108u8, 115u8, 100u8, 0u8, 116u8,
- 103u8, 0u8, 117u8, 103u8, 0u8, 117u8, 110u8, 114u8, 117u8, 122u8, 0u8,
- 121u8, 117u8, 101u8, 122u8, 104u8, 0u8,
- ])
+ ::zerovec::ZeroVec::from_bytes_unchecked(
+ b"az\0en\0ff\0kk\0ky\0mn\0pa\0sd\0tg\0uz\0yuezh\0",
+ )
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 2u8, 0u8, 0u8, 0u8, 3u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8, 0u8, 5u8, 0u8, 0u8,
- 0u8, 6u8, 0u8, 0u8, 0u8, 7u8, 0u8, 0u8, 0u8, 8u8, 0u8, 0u8, 0u8, 10u8, 0u8,
- 0u8, 0u8, 12u8, 0u8, 0u8, 0u8, 13u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8,
- 15u8, 0u8, 0u8, 0u8, 16u8, 0u8, 0u8, 0u8, 17u8, 0u8, 0u8, 0u8, 20u8, 0u8,
- 0u8, 0u8, 21u8, 0u8, 0u8, 0u8, 22u8, 0u8, 0u8, 0u8, 23u8, 0u8, 0u8, 0u8,
- 24u8, 0u8, 0u8, 0u8, 25u8, 0u8, 0u8, 0u8, 28u8, 0u8, 0u8, 0u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"\x01\0\0\0\x02\0\0\0\x03\0\0\0\x04\0\0\0\x06\0\0\0\x07\0\0\0\x08\0\0\0\x0B\0\0\0\x0C\0\0\0\r\0\0\0\x0E\0\0\0\x11\0\0\0")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 78u8, 98u8, 97u8, 116u8, 80u8, 97u8, 108u8, 109u8, 65u8, 114u8, 97u8, 98u8,
- 71u8, 108u8, 97u8, 103u8, 83u8, 104u8, 97u8, 119u8, 65u8, 100u8, 108u8,
- 109u8, 76u8, 105u8, 110u8, 98u8, 65u8, 114u8, 97u8, 98u8, 65u8, 114u8,
- 97u8, 98u8, 89u8, 101u8, 122u8, 105u8, 65u8, 114u8, 97u8, 98u8, 76u8, 97u8,
- 116u8, 110u8, 76u8, 105u8, 109u8, 98u8, 78u8, 107u8, 111u8, 111u8, 77u8,
- 111u8, 110u8, 103u8, 65u8, 114u8, 97u8, 98u8, 80u8, 104u8, 108u8, 112u8,
- 68u8, 101u8, 118u8, 97u8, 75u8, 104u8, 111u8, 106u8, 83u8, 105u8, 110u8,
- 100u8, 65u8, 114u8, 97u8, 98u8, 67u8, 121u8, 114u8, 108u8, 68u8, 101u8,
- 118u8, 97u8, 65u8, 114u8, 97u8, 98u8, 72u8, 97u8, 110u8, 115u8, 66u8,
- 111u8, 112u8, 111u8, 72u8, 97u8, 110u8, 98u8, 72u8, 97u8, 110u8, 116u8,
- ])
+ ::zerovec::ZeroVec::from_bytes_unchecked(
+ b"ArabShawAdlmArabArabLatnMongArabDevaKhojSindArabArabHansBopoHanbHant",
+ )
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 74u8, 79u8, 0u8, 83u8, 89u8, 0u8, 73u8, 82u8, 0u8, 66u8, 71u8, 0u8, 71u8,
- 66u8, 0u8, 71u8, 78u8, 0u8, 71u8, 82u8, 0u8, 67u8, 78u8, 0u8, 73u8, 81u8,
- 0u8, 71u8, 69u8, 0u8, 67u8, 78u8, 0u8, 84u8, 82u8, 0u8, 73u8, 78u8, 0u8,
- 71u8, 78u8, 0u8, 67u8, 78u8, 0u8, 80u8, 75u8, 0u8, 67u8, 78u8, 0u8, 73u8,
- 78u8, 0u8, 73u8, 78u8, 0u8, 73u8, 78u8, 0u8, 80u8, 75u8, 0u8, 75u8, 90u8,
- 0u8, 78u8, 80u8, 0u8, 65u8, 70u8, 0u8, 67u8, 78u8, 0u8, 84u8, 87u8, 0u8,
- 84u8, 87u8, 0u8, 84u8, 87u8, 0u8,
- ])
+ ::zerovec::ZeroVec::from_bytes_unchecked(
+ b"IR\0GB\0GN\0CN\0CN\0TR\0CN\0PK\0IN\0IN\0IN\0PK\0AF\0CN\0TW\0TW\0TW\0",
+ )
},
)
},
diff --git a/compiler/rustc_baked_icu_data/src/data/fallback/parents_v1/und.rs.data b/compiler/rustc_baked_icu_data/src/data/fallback/parents_v1/und.rs.data
index 5ead95908..a13646a0b 100644
--- a/compiler/rustc_baked_icu_data/src/data/fallback/parents_v1/und.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/fallback/parents_v1/und.rs.data
@@ -3,213 +3,10 @@
#[allow(unused_unsafe)]
::zerovec::ZeroMap::from_parts_unchecked(
unsafe {
- ::zerovec::VarZeroVec::from_bytes_unchecked(&[
- 131u8, 0u8, 0u8, 0u8, 0u8, 0u8, 6u8, 0u8, 11u8, 0u8, 16u8, 0u8, 21u8, 0u8,
- 26u8, 0u8, 31u8, 0u8, 36u8, 0u8, 41u8, 0u8, 46u8, 0u8, 51u8, 0u8, 56u8,
- 0u8, 61u8, 0u8, 66u8, 0u8, 71u8, 0u8, 76u8, 0u8, 81u8, 0u8, 86u8, 0u8,
- 91u8, 0u8, 96u8, 0u8, 101u8, 0u8, 106u8, 0u8, 111u8, 0u8, 116u8, 0u8,
- 121u8, 0u8, 126u8, 0u8, 131u8, 0u8, 136u8, 0u8, 141u8, 0u8, 146u8, 0u8,
- 151u8, 0u8, 156u8, 0u8, 161u8, 0u8, 166u8, 0u8, 171u8, 0u8, 176u8, 0u8,
- 181u8, 0u8, 186u8, 0u8, 191u8, 0u8, 196u8, 0u8, 201u8, 0u8, 206u8, 0u8,
- 211u8, 0u8, 216u8, 0u8, 221u8, 0u8, 226u8, 0u8, 231u8, 0u8, 236u8, 0u8,
- 241u8, 0u8, 246u8, 0u8, 251u8, 0u8, 0u8, 1u8, 5u8, 1u8, 10u8, 1u8, 15u8,
- 1u8, 20u8, 1u8, 25u8, 1u8, 30u8, 1u8, 35u8, 1u8, 40u8, 1u8, 45u8, 1u8,
- 50u8, 1u8, 55u8, 1u8, 60u8, 1u8, 65u8, 1u8, 70u8, 1u8, 75u8, 1u8, 80u8,
- 1u8, 85u8, 1u8, 90u8, 1u8, 95u8, 1u8, 100u8, 1u8, 105u8, 1u8, 110u8, 1u8,
- 115u8, 1u8, 120u8, 1u8, 125u8, 1u8, 130u8, 1u8, 135u8, 1u8, 140u8, 1u8,
- 145u8, 1u8, 150u8, 1u8, 155u8, 1u8, 160u8, 1u8, 165u8, 1u8, 170u8, 1u8,
- 175u8, 1u8, 180u8, 1u8, 185u8, 1u8, 190u8, 1u8, 195u8, 1u8, 200u8, 1u8,
- 205u8, 1u8, 210u8, 1u8, 215u8, 1u8, 220u8, 1u8, 225u8, 1u8, 230u8, 1u8,
- 235u8, 1u8, 240u8, 1u8, 245u8, 1u8, 250u8, 1u8, 255u8, 1u8, 4u8, 2u8, 9u8,
- 2u8, 14u8, 2u8, 19u8, 2u8, 24u8, 2u8, 29u8, 2u8, 34u8, 2u8, 39u8, 2u8,
- 44u8, 2u8, 49u8, 2u8, 54u8, 2u8, 59u8, 2u8, 64u8, 2u8, 71u8, 2u8, 73u8,
- 2u8, 75u8, 2u8, 77u8, 2u8, 82u8, 2u8, 87u8, 2u8, 92u8, 2u8, 97u8, 2u8,
- 102u8, 2u8, 107u8, 2u8, 112u8, 2u8, 117u8, 2u8, 122u8, 2u8, 127u8, 2u8,
- 132u8, 2u8, 101u8, 110u8, 45u8, 49u8, 53u8, 48u8, 101u8, 110u8, 45u8, 65u8,
- 71u8, 101u8, 110u8, 45u8, 65u8, 73u8, 101u8, 110u8, 45u8, 65u8, 84u8,
- 101u8, 110u8, 45u8, 65u8, 85u8, 101u8, 110u8, 45u8, 66u8, 66u8, 101u8,
- 110u8, 45u8, 66u8, 69u8, 101u8, 110u8, 45u8, 66u8, 77u8, 101u8, 110u8,
- 45u8, 66u8, 83u8, 101u8, 110u8, 45u8, 66u8, 87u8, 101u8, 110u8, 45u8, 66u8,
- 90u8, 101u8, 110u8, 45u8, 67u8, 67u8, 101u8, 110u8, 45u8, 67u8, 72u8,
- 101u8, 110u8, 45u8, 67u8, 75u8, 101u8, 110u8, 45u8, 67u8, 77u8, 101u8,
- 110u8, 45u8, 67u8, 88u8, 101u8, 110u8, 45u8, 67u8, 89u8, 101u8, 110u8,
- 45u8, 68u8, 69u8, 101u8, 110u8, 45u8, 68u8, 71u8, 101u8, 110u8, 45u8, 68u8,
- 75u8, 101u8, 110u8, 45u8, 68u8, 77u8, 101u8, 110u8, 45u8, 69u8, 82u8,
- 101u8, 110u8, 45u8, 70u8, 73u8, 101u8, 110u8, 45u8, 70u8, 74u8, 101u8,
- 110u8, 45u8, 70u8, 75u8, 101u8, 110u8, 45u8, 70u8, 77u8, 101u8, 110u8,
- 45u8, 71u8, 66u8, 101u8, 110u8, 45u8, 71u8, 68u8, 101u8, 110u8, 45u8, 71u8,
- 71u8, 101u8, 110u8, 45u8, 71u8, 72u8, 101u8, 110u8, 45u8, 71u8, 73u8,
- 101u8, 110u8, 45u8, 71u8, 77u8, 101u8, 110u8, 45u8, 71u8, 89u8, 101u8,
- 110u8, 45u8, 72u8, 75u8, 101u8, 110u8, 45u8, 73u8, 69u8, 101u8, 110u8,
- 45u8, 73u8, 76u8, 101u8, 110u8, 45u8, 73u8, 77u8, 101u8, 110u8, 45u8, 73u8,
- 78u8, 101u8, 110u8, 45u8, 73u8, 79u8, 101u8, 110u8, 45u8, 74u8, 69u8,
- 101u8, 110u8, 45u8, 74u8, 77u8, 101u8, 110u8, 45u8, 75u8, 69u8, 101u8,
- 110u8, 45u8, 75u8, 73u8, 101u8, 110u8, 45u8, 75u8, 78u8, 101u8, 110u8,
- 45u8, 75u8, 89u8, 101u8, 110u8, 45u8, 76u8, 67u8, 101u8, 110u8, 45u8, 76u8,
- 82u8, 101u8, 110u8, 45u8, 76u8, 83u8, 101u8, 110u8, 45u8, 77u8, 71u8,
- 101u8, 110u8, 45u8, 77u8, 79u8, 101u8, 110u8, 45u8, 77u8, 83u8, 101u8,
- 110u8, 45u8, 77u8, 84u8, 101u8, 110u8, 45u8, 77u8, 85u8, 101u8, 110u8,
- 45u8, 77u8, 86u8, 101u8, 110u8, 45u8, 77u8, 87u8, 101u8, 110u8, 45u8, 77u8,
- 89u8, 101u8, 110u8, 45u8, 78u8, 65u8, 101u8, 110u8, 45u8, 78u8, 70u8,
- 101u8, 110u8, 45u8, 78u8, 71u8, 101u8, 110u8, 45u8, 78u8, 76u8, 101u8,
- 110u8, 45u8, 78u8, 82u8, 101u8, 110u8, 45u8, 78u8, 85u8, 101u8, 110u8,
- 45u8, 78u8, 90u8, 101u8, 110u8, 45u8, 80u8, 71u8, 101u8, 110u8, 45u8, 80u8,
- 75u8, 101u8, 110u8, 45u8, 80u8, 78u8, 101u8, 110u8, 45u8, 80u8, 87u8,
- 101u8, 110u8, 45u8, 82u8, 87u8, 101u8, 110u8, 45u8, 83u8, 66u8, 101u8,
- 110u8, 45u8, 83u8, 67u8, 101u8, 110u8, 45u8, 83u8, 68u8, 101u8, 110u8,
- 45u8, 83u8, 69u8, 101u8, 110u8, 45u8, 83u8, 71u8, 101u8, 110u8, 45u8, 83u8,
- 72u8, 101u8, 110u8, 45u8, 83u8, 73u8, 101u8, 110u8, 45u8, 83u8, 76u8,
- 101u8, 110u8, 45u8, 83u8, 83u8, 101u8, 110u8, 45u8, 83u8, 88u8, 101u8,
- 110u8, 45u8, 83u8, 90u8, 101u8, 110u8, 45u8, 84u8, 67u8, 101u8, 110u8,
- 45u8, 84u8, 75u8, 101u8, 110u8, 45u8, 84u8, 79u8, 101u8, 110u8, 45u8, 84u8,
- 84u8, 101u8, 110u8, 45u8, 84u8, 86u8, 101u8, 110u8, 45u8, 84u8, 90u8,
- 101u8, 110u8, 45u8, 85u8, 71u8, 101u8, 110u8, 45u8, 86u8, 67u8, 101u8,
- 110u8, 45u8, 86u8, 71u8, 101u8, 110u8, 45u8, 86u8, 85u8, 101u8, 110u8,
- 45u8, 87u8, 83u8, 101u8, 110u8, 45u8, 90u8, 65u8, 101u8, 110u8, 45u8, 90u8,
- 77u8, 101u8, 110u8, 45u8, 90u8, 87u8, 101u8, 115u8, 45u8, 65u8, 82u8,
- 101u8, 115u8, 45u8, 66u8, 79u8, 101u8, 115u8, 45u8, 66u8, 82u8, 101u8,
- 115u8, 45u8, 66u8, 90u8, 101u8, 115u8, 45u8, 67u8, 76u8, 101u8, 115u8,
- 45u8, 67u8, 79u8, 101u8, 115u8, 45u8, 67u8, 82u8, 101u8, 115u8, 45u8, 67u8,
- 85u8, 101u8, 115u8, 45u8, 68u8, 79u8, 101u8, 115u8, 45u8, 69u8, 67u8,
- 101u8, 115u8, 45u8, 71u8, 84u8, 101u8, 115u8, 45u8, 72u8, 78u8, 101u8,
- 115u8, 45u8, 77u8, 88u8, 101u8, 115u8, 45u8, 78u8, 73u8, 101u8, 115u8,
- 45u8, 80u8, 65u8, 101u8, 115u8, 45u8, 80u8, 69u8, 101u8, 115u8, 45u8, 80u8,
- 82u8, 101u8, 115u8, 45u8, 80u8, 89u8, 101u8, 115u8, 45u8, 83u8, 86u8,
- 101u8, 115u8, 45u8, 85u8, 83u8, 101u8, 115u8, 45u8, 85u8, 89u8, 101u8,
- 115u8, 45u8, 86u8, 69u8, 104u8, 105u8, 45u8, 76u8, 97u8, 116u8, 110u8,
- 104u8, 116u8, 110u8, 98u8, 110u8, 110u8, 112u8, 116u8, 45u8, 65u8, 79u8,
- 112u8, 116u8, 45u8, 67u8, 72u8, 112u8, 116u8, 45u8, 67u8, 86u8, 112u8,
- 116u8, 45u8, 70u8, 82u8, 112u8, 116u8, 45u8, 71u8, 81u8, 112u8, 116u8,
- 45u8, 71u8, 87u8, 112u8, 116u8, 45u8, 76u8, 85u8, 112u8, 116u8, 45u8, 77u8,
- 79u8, 112u8, 116u8, 45u8, 77u8, 90u8, 112u8, 116u8, 45u8, 83u8, 84u8,
- 112u8, 116u8, 45u8, 84u8, 76u8, 122u8, 104u8, 45u8, 72u8, 97u8, 110u8,
- 116u8, 45u8, 77u8, 79u8,
- ])
+ :: zerovec :: VarZeroVec :: from_bytes_unchecked (b"\x84\0\0\0\0\0\x06\0\x0B\0\x10\0\x15\0\x1A\0\x1F\0$\0)\0.\x003\08\0=\0B\0G\0L\0Q\0V\0[\0`\0e\0j\0o\0t\0y\0~\0\x83\0\x88\0\x8D\0\x92\0\x97\0\x9C\0\xA1\0\xA6\0\xAB\0\xB0\0\xB5\0\xBA\0\xBF\0\xC4\0\xC9\0\xCE\0\xD3\0\xD8\0\xDD\0\xE2\0\xE7\0\xEC\0\xF1\0\xF6\0\xFB\0\0\x01\x05\x01\n\x01\x0F\x01\x14\x01\x19\x01\x1E\x01#\x01(\x01-\x012\x017\x01<\x01A\x01F\x01K\x01P\x01U\x01Z\x01_\x01d\x01i\x01n\x01s\x01x\x01}\x01\x82\x01\x87\x01\x8C\x01\x91\x01\x96\x01\x9B\x01\xA0\x01\xA5\x01\xAA\x01\xAF\x01\xB4\x01\xB9\x01\xBE\x01\xC3\x01\xC8\x01\xCD\x01\xD2\x01\xD7\x01\xDC\x01\xE1\x01\xE6\x01\xEB\x01\xF0\x01\xF5\x01\xFA\x01\xFF\x01\x04\x02\t\x02\x0E\x02\x13\x02\x18\x02\x1D\x02\"\x02'\x02,\x021\x026\x02;\x02@\x02G\x02I\x02K\x02M\x02R\x02W\x02\\\x02a\x02f\x02k\x02p\x02u\x02z\x02\x7F\x02\x84\x02\x89\x02en-150en-AGen-AIen-ATen-AUen-BBen-BEen-BMen-BSen-BWen-BZen-CCen-CHen-CKen-CMen-CXen-CYen-DEen-DGen-DKen-DMen-ERen-FIen-FJen-FKen-FMen-GBen-GDen-GGen-GHen-GIen-GMen-GYen-HKen-IEen-ILen-IMen-INen-IOen-JEen-JMen-KEen-KIen-KNen-KYen-LCen-LRen-LSen-MGen-MOen-MSen-MTen-MUen-MVen-MWen-MYen-NAen-NFen-NGen-NLen-NRen-NUen-NZen-PGen-PKen-PNen-PWen-RWen-SBen-SCen-SDen-SEen-SGen-SHen-SIen-SLen-SSen-SXen-SZen-TCen-TKen-TOen-TTen-TVen-TZen-UGen-VCen-VGen-VUen-WSen-ZAen-ZMen-ZWes-ARes-BOes-BRes-BZes-CLes-COes-CRes-CUes-DOes-ECes-GTes-HNes-MXes-NIes-PAes-PEes-PRes-PYes-SVes-USes-UYes-VEhi-Latnhtnbnnno-NOpt-AOpt-CHpt-CVpt-FRpt-GQpt-GWpt-LUpt-MOpt-MZpt-STpt-TLzh-Hant-MO")
},
unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 49u8, 53u8, 48u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 49u8, 53u8, 48u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 48u8, 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8,
- 48u8, 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8,
- 49u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8,
- 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8,
- 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 48u8, 48u8, 49u8, 101u8, 115u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8,
- 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8,
- 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8,
- 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8,
- 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 1u8, 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 52u8, 49u8, 57u8, 101u8, 115u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 52u8,
- 49u8, 57u8, 101u8, 110u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 73u8, 78u8,
- 0u8, 102u8, 114u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 72u8, 84u8, 0u8,
- 110u8, 111u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 110u8,
- 111u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 112u8, 116u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 112u8, 116u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 80u8, 84u8, 0u8, 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8,
- 80u8, 84u8, 0u8, 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8,
- 84u8, 0u8, 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8,
- 0u8, 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8,
- 112u8, 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 112u8,
- 116u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 112u8, 116u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 112u8, 116u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 1u8, 80u8, 84u8, 0u8, 122u8, 104u8, 0u8, 1u8, 72u8,
- 97u8, 110u8, 116u8, 1u8, 72u8, 75u8, 0u8,
- ])
+ :: zerovec :: ZeroVec :: from_bytes_unchecked (b"en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01150en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001en\0\0\0\0\0\0\x01001es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419es\0\0\0\0\0\0\x01419en\0\0\0\0\0\0\x01IN\0fr\0\0\0\0\0\0\x01HT\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0no\0\0\0\0\0\0\0\0\0\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0pt\0\0\0\0\0\0\x01PT\0zh\0\x01Hant\x01HK\0")
},
)
},
diff --git a/compiler/rustc_baked_icu_data/src/data/fallback/supplement/co_v1/und.rs.data b/compiler/rustc_baked_icu_data/src/data/fallback/supplement/co_v1/und.rs.data
index 7d70e78c3..647f8f516 100644
--- a/compiler/rustc_baked_icu_data/src/data/fallback/supplement/co_v1/und.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/fallback/supplement/co_v1/und.rs.data
@@ -2,34 +2,20 @@
parents: unsafe {
#[allow(unused_unsafe)]
::zerovec::ZeroMap::from_parts_unchecked(
- unsafe {
- ::zerovec::VarZeroVec::from_bytes_unchecked(&[
- 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 121u8, 117u8, 101u8,
- ])
- },
- unsafe {
- ::zerovec::ZeroVec::from_bytes_unchecked(&[
- 122u8, 104u8, 0u8, 1u8, 72u8, 97u8, 110u8, 116u8, 0u8, 0u8, 0u8, 0u8,
- ])
- },
+ unsafe { ::zerovec::VarZeroVec::from_bytes_unchecked(b"\x01\0\0\0\0\0yue") },
+ unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(b"zh\0\x01Hant\0\0\0\0") },
)
},
unicode_extension_defaults: unsafe {
#[allow(unused_unsafe)]
::zerovec::ZeroMap2d::from_parts_unchecked(
- unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(&[99u8, 111u8]) },
- unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(&[2u8, 0u8, 0u8, 0u8]) },
+ unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(b"co") },
+ unsafe { ::zerovec::ZeroVec::from_bytes_unchecked(b"\x02\0\0\0") },
unsafe {
- ::zerovec::VarZeroVec::from_bytes_unchecked(&[
- 2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 122u8, 104u8, 122u8, 104u8, 45u8,
- 72u8, 97u8, 110u8, 116u8,
- ])
+ ::zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x02\0zhzh-Hant")
},
unsafe {
- ::zerovec::VarZeroVec::from_bytes_unchecked(&[
- 2u8, 0u8, 0u8, 0u8, 0u8, 0u8, 6u8, 0u8, 112u8, 105u8, 110u8, 121u8, 105u8,
- 110u8, 115u8, 116u8, 114u8, 111u8, 107u8, 101u8,
- ])
+ ::zerovec::VarZeroVec::from_bytes_unchecked(b"\x02\0\0\0\0\0\x06\0pinyinstroke")
},
)
},
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/en.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/en.rs.data
index cb5cbfa87..4bf244019 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/en.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/en.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", and ", 6u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", and ", 6u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" and ", 5u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" and ", 5u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", & ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", & ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" & ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" & ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/es.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/es.rs.data
index 51f910975..84de7cd01 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/es.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/es.rs.data
@@ -1,836 +1,116 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" y ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" y ", 3u8),
special_case: Some(::icu_list::provider::SpecialCasePattern {
condition: unsafe {
::icu_list::provider::SerdeDFA::from_dfa_bytes_unchecked(
if cfg!(target_endian = "little") {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 255u8, 254u8, 0u8, 0u8, 2u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 40u8, 1u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 4u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 9u8,
- 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8,
- 0u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\xFF\xFE\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B(\x01\0\0\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\x04\0\0\0\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#\0\0\0"
} else {
- &[
- 114u8, 117u8, 115u8, 116u8, 45u8, 114u8, 101u8, 103u8, 101u8,
- 120u8, 45u8, 97u8, 117u8, 116u8, 111u8, 109u8, 97u8, 116u8, 97u8,
- 45u8, 100u8, 102u8, 97u8, 45u8, 115u8, 112u8, 97u8, 114u8, 115u8,
- 101u8, 0u8, 0u8, 0u8, 0u8, 254u8, 255u8, 0u8, 0u8, 0u8, 2u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 2u8,
- 2u8, 2u8, 3u8, 4u8, 4u8, 5u8, 6u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8, 7u8,
- 7u8, 7u8, 7u8, 7u8, 8u8, 9u8, 9u8, 9u8, 10u8, 11u8, 11u8, 12u8,
- 13u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8, 14u8,
- 14u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 15u8,
- 15u8, 15u8, 15u8, 15u8, 15u8, 15u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8, 16u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8,
- 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 17u8, 18u8,
- 18u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8,
- 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 19u8, 20u8, 21u8,
- 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8, 21u8,
- 22u8, 23u8, 23u8, 24u8, 25u8, 25u8, 25u8, 26u8, 27u8, 27u8, 27u8,
- 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 27u8, 0u8, 0u8, 1u8,
- 40u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 1u8, 128u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 1u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 5u8, 0u8, 5u8,
- 5u8, 6u8, 6u8, 12u8, 12u8, 13u8, 13u8, 0u8, 0u8, 83u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 83u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 0u8, 27u8, 0u8, 0u8, 18u8, 0u8,
- 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 0u8, 3u8, 0u8, 6u8, 6u8, 13u8, 13u8,
- 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 104u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 14u8, 0u8, 0u8, 0u8, 2u8, 2u8, 4u8, 7u8, 9u8, 9u8,
- 11u8, 14u8, 19u8, 19u8, 20u8, 20u8, 21u8, 21u8, 22u8, 22u8, 23u8,
- 23u8, 24u8, 24u8, 25u8, 25u8, 26u8, 26u8, 0u8, 0u8, 68u8, 0u8, 0u8,
- 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8, 68u8, 0u8, 0u8, 0u8,
- 68u8, 0u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 206u8, 0u8, 0u8, 0u8,
- 221u8, 0u8, 0u8, 0u8, 236u8, 0u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 251u8, 0u8, 0u8, 0u8, 10u8, 1u8, 0u8, 0u8, 25u8, 1u8, 0u8, 0u8,
- 18u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 68u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 17u8, 17u8, 0u8,
- 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8,
- 17u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8,
- 0u8, 15u8, 16u8, 0u8, 0u8, 191u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 2u8, 0u8, 16u8, 17u8, 0u8, 0u8, 221u8, 0u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 17u8, 0u8, 0u8, 221u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 2u8, 0u8, 15u8, 15u8, 0u8,
- 0u8, 221u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8,
- 4u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8,
- 0u8, 0u8, 9u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8, 0u8, 18u8, 0u8, 0u8,
- 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 0u8, 35u8, 0u8, 0u8, 0u8,
- 35u8,
- ]
+ b"rust-regex-automata-dfa-sparse\0\0\0\0\xFE\xFF\0\0\0\x02\0\0\0\0\0\0\0\x0E\0\0\0\x01\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\0\x01\x02\x02\x02\x03\x04\x04\x05\x06\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x07\x08\t\t\t\n\x0B\x0B\x0C\r\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0E\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x0F\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x10\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x11\x12\x12\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x13\x14\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x15\x16\x17\x17\x18\x19\x19\x19\x1A\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\x1B\0\0\x01(\x01\0\0\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x01\x80\0\0\0\0\0\0\x01\0\0\0\0\0\0\0\0\x05\0\x05\x05\x06\x06\x0C\x0C\r\r\0\0S\0\0\0D\0\0\0S\0\0\0D\0\0\0\0\0\0\0\0\x02\0\0\x1B\0\0\x12\0\0\0\x12\0\0\0\0\x03\0\x06\x06\r\r\0\0h\0\0\0h\0\0\0\0\0\0\0\0\x0E\0\0\0\x02\x02\x04\x07\t\t\x0B\x0E\x13\x13\x14\x14\x15\x15\x16\x16\x17\x17\x18\x18\x19\x19\x1A\x1A\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0D\0\0\0\xBF\0\0\0\xCE\0\0\0\xDD\0\0\0\xEC\0\0\0\xDD\0\0\0\xFB\0\0\0\n\x01\0\0\x19\x01\0\0\x12\0\0\0\0\x02\0\x0F\x11\0\0D\0\0\0\0\0\0\0\0\x02\0\x11\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x0F\x10\0\0\xBF\0\0\0\0\0\0\0\0\x02\0\x10\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x11\0\0\xDD\0\0\0\0\0\0\0\0\x02\0\x0F\x0F\0\0\xDD\0\0\0\0\0\0\0\0\0\0\0\x04\0\0\0\0#\0\0\0#\0\0\0#\0\0\0#\0\0\0\0\0\0#\0\0\0\t\0\0\0\x12\0\0\0\x12\0\0\0\0\0\0\0\0\0\0\0#\0\0\0#"
},
)
},
- pattern: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ pattern: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
}),
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/fr.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/fr.rs.data
index 66ec8f600..79a97e50f 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/fr.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/fr.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" et ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" et ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" et ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" et ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" et ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/it.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/it.rs.data
index cbccf1120..b976b6cb6 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/it.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/it.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/ja.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/ja.rs.data
index 9fd168375..d76d567eb 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/ja.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/ja.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/pt.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/pt.rs.data
index 403975213..3d8c89f90 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/pt.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/pt.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" e ", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" e ", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/ru.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/ru.rs.data
index 933cb85c8..653ce28d6 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/ru.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/ru.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" и ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" и ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" и ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" и ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" и ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/tr.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/tr.rs.data
index 286eaf69f..9fa6eb56a 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/tr.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/tr.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" ve ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" ve ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" ve ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(" ve ", 4u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(" ve ", 4u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/und.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/und.rs.data
index 2d2c9bcec..66b55c253 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/und.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/und.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked(", ", 2u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts(", ", 2u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh-Hant.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh-Hant.rs.data
index 5d96cc85e..38da6ecf8 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh-Hant.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh-Hant.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh.rs.data b/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh.rs.data
index 4a38374ca..d4dac1c38 100644
--- a/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh.rs.data
+++ b/compiler/rustc_baked_icu_data/src/data/list/and_v1/zh.rs.data
@@ -1,74 +1,50 @@
::icu_list::provider::ListFormatterPatternsV1([
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("和", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("和", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
::icu_list::provider::ConditionalListJoinerPattern {
- default: unsafe {
- ::icu_list::provider::ListJoinerPattern::from_parts_unchecked("、", 3u8)
- },
+ default: ::icu_list::provider::ListJoinerPattern::from_parts("、", 3u8),
special_case: None,
},
])
diff --git a/compiler/rustc_baked_icu_data/src/data/mod.rs b/compiler/rustc_baked_icu_data/src/data/mod.rs
index ce33339ad..943187808 100644
--- a/compiler/rustc_baked_icu_data/src/data/mod.rs
+++ b/compiler/rustc_baked_icu_data/src/data/mod.rs
@@ -1,7 +1,10 @@
// @generated
+#[clippy::msrv = "1.61"]
mod fallback;
+#[clippy::msrv = "1.61"]
mod list;
-use ::icu_provider::prelude::*;
+#[clippy::msrv = "1.61"]
+use icu_provider::prelude::*;
/// Implement [`DataProvider<M>`] on the given struct using the data
/// hardcoded in this module. This allows the struct to be used with
/// `icu`'s `_unstable` constructors.
@@ -17,6 +20,7 @@ use ::icu_provider::prelude::*;
#[allow(unused_macros)]
macro_rules! impl_data_provider {
($ provider : path) => {
+ #[clippy::msrv = "1.61"]
impl DataProvider<::icu_list::provider::AndListV1Marker> for $provider {
fn load(&self, req: DataRequest) -> Result<DataResponse<::icu_list::provider::AndListV1Marker>, DataError> {
list::and_v1::lookup(&req.locale)
@@ -26,6 +30,7 @@ macro_rules! impl_data_provider {
.ok_or_else(|| DataErrorKind::MissingLocale.with_req(::icu_list::provider::AndListV1Marker::KEY, req))
}
}
+ #[clippy::msrv = "1.61"]
impl DataProvider<::icu_provider_adapters::fallback::provider::CollationFallbackSupplementV1Marker> for $provider {
fn load(
&self,
@@ -41,6 +46,7 @@ macro_rules! impl_data_provider {
})
}
}
+ #[clippy::msrv = "1.61"]
impl DataProvider<::icu_provider_adapters::fallback::provider::LocaleFallbackLikelySubtagsV1Marker> for $provider {
fn load(
&self,
@@ -56,6 +62,7 @@ macro_rules! impl_data_provider {
})
}
}
+ #[clippy::msrv = "1.61"]
impl DataProvider<::icu_provider_adapters::fallback::provider::LocaleFallbackParentsV1Marker> for $provider {
fn load(
&self,
@@ -87,6 +94,7 @@ macro_rules! impl_data_provider {
#[allow(unused_macros)]
macro_rules! impl_any_provider {
($ provider : path) => {
+ #[clippy::msrv = "1.61"]
impl AnyProvider for $provider {
fn load_any(&self, key: DataKey, req: DataRequest) -> Result<AnyResponse, DataError> {
const ANDLISTV1MARKER: ::icu_provider::DataKeyHash = ::icu_list::provider::AndListV1Marker::KEY.hashed();
@@ -109,5 +117,6 @@ macro_rules! impl_any_provider {
}
};
}
+#[clippy::msrv = "1.61"]
pub struct BakedDataProvider;
impl_data_provider!(BakedDataProvider);
diff --git a/compiler/rustc_borrowck/Cargo.toml b/compiler/rustc_borrowck/Cargo.toml
index 87c113f3e..56a9deb6a 100644
--- a/compiler/rustc_borrowck/Cargo.toml
+++ b/compiler/rustc_borrowck/Cargo.toml
@@ -15,12 +15,12 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
-rustc_const_eval = { path = "../rustc_const_eval" }
rustc_mir_dataflow = { path = "../rustc_mir_dataflow" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_borrowck/messages.ftl b/compiler/rustc_borrowck/messages.ftl
index a3b6b5e81..67fdb6717 100644
--- a/compiler/rustc_borrowck/messages.ftl
+++ b/compiler/rustc_borrowck/messages.ftl
@@ -1,129 +1,264 @@
-borrowck_move_unsized =
- cannot move a value of type `{$ty}`
- .label = the size of `{$ty}` cannot be statically determined
+borrowck_assign_due_to_use_closure =
+ assignment occurs due to use in closure
-borrowck_higher_ranked_lifetime_error =
- higher-ranked lifetime error
+borrowck_assign_due_to_use_generator =
+ assign occurs due to use in generator
-borrowck_could_not_prove =
- could not prove `{$predicate}`
+borrowck_assign_part_due_to_use_closure =
+ assignment to part occurs due to use in closure
+
+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_borrow_due_to_use_generator =
+ borrow occurs due to use in generator
+
+borrowck_calling_operator_moves_lhs =
+ calling this operator moves the left-hand side
+
+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
+
+borrowck_capture_immute =
+ capture is immutable because of use here
+
+borrowck_capture_move =
+ capture is moved because of use here
+
+borrowck_capture_mut =
+ capture is mutable because of use here
+
+borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
+
+borrowck_closure_invoked_twice =
+ closure cannot be invoked more than once because it moves the variable `{$place_name}` out of its environment
+
+borrowck_closure_moved_twice =
+ closure cannot be moved more than once as it is not `Copy` due to moving the variable `{$place_name}` out of its environment
+
+borrowck_consider_borrow_type_contents =
+ help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents
borrowck_could_not_normalize =
could not normalize `{$value}`
-borrowck_higher_ranked_subtype_error =
- higher-ranked subtype error
+borrowck_could_not_prove =
+ could not prove `{$predicate}`
+
+borrowck_func_take_self_moved_place =
+ `{$func}` takes ownership of the receiver `self`, which moves {$place_name}
borrowck_generic_does_not_live_long_enough =
`{$kind}` does not live long enough
+borrowck_higher_ranked_lifetime_error =
+ higher-ranked lifetime error
+
+borrowck_higher_ranked_subtype_error =
+ higher-ranked subtype error
+
+borrowck_lifetime_constraints_error =
+ lifetime may not live long enough
+
borrowck_move_borrowed =
cannot move out of `{$desc}` because it is borrowed
-borrowck_var_does_not_need_mut =
- variable does not need to be mutable
- .suggestion = remove this `mut`
+borrowck_move_out_place_here =
+ {$place} is moved here
-borrowck_var_cannot_escape_closure =
- captured variable cannot escape `FnMut` closure body
- .note = `FnMut` closures only have access to their captured variables while they are executing...
- .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
+borrowck_move_unsized =
+ cannot move a value of type `{$ty}`
+ .label = the size of `{$ty}` cannot be statically determined
-borrowck_var_here_defined = variable defined here
+borrowck_moved_a_fn_once_in_call =
+ this value implements `FnOnce`, which causes it to be moved when called
-borrowck_var_here_captured = variable captured here
+borrowck_moved_due_to_await =
+ {$place_name} {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to this {$is_loop_message ->
+ [true] await, in previous iteration of loop
+ *[false] await
+ }
-borrowck_closure_inferred_mut = inferred to be a `FnMut` closure
+borrowck_moved_due_to_call =
+ {$place_name} {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to this {$is_loop_message ->
+ [true] call, in previous iteration of loop
+ *[false] call
+ }
-borrowck_returned_closure_escaped =
- returns a closure that contains a reference to a captured variable, which then escapes the closure body
+borrowck_moved_due_to_implicit_into_iter_call =
+ {$place_name} {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to this implicit call to {$is_loop_message ->
+ [true] `.into_iter()`, in previous iteration of loop
+ *[false] `.into_iter()`
+ }
+
+borrowck_moved_due_to_method_call =
+ {$place_name} {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to this method {$is_loop_message ->
+ [true] call, in previous iteration of loop
+ *[false] call
+ }
+
+borrowck_moved_due_to_usage_in_operator =
+ {$place_name} {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to usage in {$is_loop_message ->
+ [true] operator, in previous iteration of loop
+ *[false] operator
+ }
+
+borrowck_opaque_type_non_generic_param =
+ expected generic {$kind} parameter, found `{$ty}`
+ .label = {STREQ($ty, "'static") ->
+ [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
+ *[other] this generic parameter must be used with a generic {$kind} parameter
+ }
+
+borrowck_partial_var_move_by_use_in_closure =
+ variable {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to use in closure
+
+borrowck_partial_var_move_by_use_in_generator =
+ variable {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } due to use in generator
borrowck_returned_async_block_escaped =
returns an `async` block that contains a reference to a captured variable, which then escapes the closure body
-borrowck_returned_ref_escaped =
- returns a reference to a captured variable which escapes the closure body
+borrowck_returned_closure_escaped =
+ returns a closure that contains a reference to a captured variable, which then escapes the closure body
-borrowck_lifetime_constraints_error =
- lifetime may not live long enough
+borrowck_returned_lifetime_short =
+ {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
borrowck_returned_lifetime_wrong =
{$mir_def_name} was supposed to return data with lifetime `{$outlived_fr_name}` but it is returning data with lifetime `{$fr_name}`
-borrowck_returned_lifetime_short =
- {$category_desc}requires that `{$free_region_name}` must outlive `{$outlived_fr_name}`
+borrowck_returned_ref_escaped =
+ returns a reference to a captured variable which escapes the closure body
+
+borrowck_suggest_create_freash_reborrow =
+ consider reborrowing the `Pin` instead of moving it
+
+borrowck_suggest_iterate_over_slice =
+ consider iterating over a slice of the `{$ty}`'s content to avoid moving into the `for` loop
+
+borrowck_ty_no_impl_copy =
+ {$is_partial_move ->
+ [true] partial move
+ *[false] move
+ } occurs because {$place} has type `{$ty}`, which does not implement the `Copy` trait
+
+borrowck_use_due_to_use_closure =
+ use occurs due to use in closure
+
+borrowck_use_due_to_use_generator =
+ use occurs due to use in generator
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_value_capture_here =
+ value captured {$is_within ->
+ [true] here by generator
+ *[false] here
+ }
-borrowck_var_borrow_by_use_place_in_closure =
- borrow occurs due to use of {$place} in closure
+borrowck_value_moved_here =
+ value {$is_partial ->
+ [true] partially moved
+ *[false] moved
+ } {$is_move_msg ->
+ [true] into closure here
+ *[false] here
+ }{$is_loop_message ->
+ [true] , in previous iteration of loop
+ *[false] {""}
+ }
-borrowck_var_borrow_by_use_place =
- borrow occurs due to use of {$place}
+borrowck_var_borrow_by_use_in_closure =
+ borrow occurs due to use in closure
-borrowck_borrow_due_to_use_generator =
+borrowck_var_borrow_by_use_in_generator =
borrow occurs due to use in generator
-borrowck_use_due_to_use_generator =
- use occurs due to use in generator
+borrowck_var_borrow_by_use_place_in_closure =
+ {$is_single_var ->
+ *[true] borrow occurs
+ [false] borrows occur
+ } due to use of {$place} in closure
-borrowck_assign_due_to_use_generator =
- assign occurs due to use in generator
+borrowck_var_borrow_by_use_place_in_generator =
+ {$is_single_var ->
+ *[true] borrow occurs
+ [false] borrows occur
+ } due to use of {$place} in generator
-borrowck_assign_part_due_to_use_generator =
- assign to part occurs due to use in generator
+borrowck_var_cannot_escape_closure =
+ captured variable cannot escape `FnMut` closure body
+ .note = `FnMut` closures only have access to their captured variables while they are executing...
+ .cannot_escape = ...therefore, they cannot allow references to captured variables to escape
-borrowck_borrow_due_to_use_closure =
- borrow occurs due to use in closure
+borrowck_var_does_not_need_mut =
+ variable does not need to be mutable
+ .suggestion = remove this `mut`
-borrowck_use_due_to_use_closure =
- use occurs due to use in closure
+borrowck_var_first_borrow_by_use_place_in_closure =
+ first borrow occurs due to use of {$place} in closure
-borrowck_assign_due_to_use_closure =
- assignment occurs due to use in closure
+borrowck_var_first_borrow_by_use_place_in_generator =
+ first borrow occurs due to use of {$place} in generator
-borrowck_assign_part_due_to_use_closure =
- assignment to part occurs due to use in closure
+borrowck_var_here_captured = variable captured here
-borrowck_capture_immute =
- capture is immutable because of use here
+borrowck_var_here_defined = variable defined here
-borrowck_capture_mut =
- capture is mutable because of use here
+borrowck_var_move_by_use_in_closure =
+ move occurs due to use in closure
-borrowck_capture_move =
- capture is moved because of use here
+borrowck_var_move_by_use_in_generator =
+ move occurs due to use in generator
+
+borrowck_var_move_by_use_place_in_closure =
+ move occurs due to use of {$place} in closure
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_var_mutable_borrow_by_use_place_in_closure =
+ mutable borrow 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
+borrowck_var_second_borrow_by_use_place_in_closure =
+ second borrow occurs due to use of {$place} in closure
-borrowck_opaque_type_non_generic_param =
- expected generic {$kind} parameter, found `{$ty}`
- .label = {STREQ($ty, "'static") ->
- [true] cannot use static lifetime; use a bound lifetime instead or remove the lifetime parameter from the opaque type
- *[other] this generic parameter must be used with a generic {$kind} parameter
- }
+borrowck_var_second_borrow_by_use_place_in_generator =
+ second borrow occurs due to use of {$place} in generator
diff --git a/compiler/rustc_borrowck/src/borrow_set.rs b/compiler/rustc_borrowck/src/borrow_set.rs
index 4824f6346..6be20b097 100644
--- a/compiler/rustc_borrowck/src/borrow_set.rs
+++ b/compiler/rustc_borrowck/src/borrow_set.rs
@@ -30,7 +30,7 @@ pub struct BorrowSet<'tcx> {
/// Map from local to all the borrows on that local.
pub local_map: FxIndexMap<mir::Local, FxIndexSet<BorrowIndex>>,
- pub(crate) locals_state_at_exit: LocalsStateAtExit,
+ pub locals_state_at_exit: LocalsStateAtExit,
}
impl<'tcx> Index<BorrowIndex> for BorrowSet<'tcx> {
@@ -153,7 +153,7 @@ impl<'tcx> BorrowSet<'tcx> {
self.activation_map.get(&location).map_or(&[], |activations| &activations[..])
}
- pub(crate) fn len(&self) -> usize {
+ pub fn len(&self) -> usize {
self.location_map.len()
}
diff --git a/compiler/rustc_borrowck/src/borrowck_errors.rs b/compiler/rustc_borrowck/src/borrowck_errors.rs
index 2bbb9618d..acca1a147 100644
--- a/compiler/rustc_borrowck/src/borrowck_errors.rs
+++ b/compiler/rustc_borrowck/src/borrowck_errors.rs
@@ -469,6 +469,7 @@ impl<'cx, 'tcx> crate::MirBorrowckCtxt<'cx, 'tcx> {
}
#[rustc_lint_diagnostics]
+ #[track_caller]
pub(crate) fn struct_span_err_with_code<S: Into<MultiSpan>>(
&self,
sp: S,
diff --git a/compiler/rustc_borrowck/src/constraints/graph.rs b/compiler/rustc_borrowck/src/constraints/graph.rs
index f5a34cb05..8b7d9ec2c 100644
--- a/compiler/rustc_borrowck/src/constraints/graph.rs
+++ b/compiler/rustc_borrowck/src/constraints/graph.rs
@@ -1,5 +1,5 @@
use rustc_data_structures::graph;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use rustc_span::DUMMY_SP;
diff --git a/compiler/rustc_borrowck/src/constraints/mod.rs b/compiler/rustc_borrowck/src/constraints/mod.rs
index d2d9779db..315886bbe 100644
--- a/compiler/rustc_borrowck/src/constraints/mod.rs
+++ b/compiler/rustc_borrowck/src/constraints/mod.rs
@@ -2,7 +2,7 @@
#![deny(rustc::diagnostic_outside_of_impl)]
use rustc_data_structures::graph::scc::Sccs;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{RegionVid, VarianceDiagInfo};
use rustc_span::Span;
diff --git a/compiler/rustc_borrowck/src/consumers.rs b/compiler/rustc_borrowck/src/consumers.rs
index cb1a65222..d25714537 100644
--- a/compiler/rustc_borrowck/src/consumers.rs
+++ b/compiler/rustc_borrowck/src/consumers.rs
@@ -3,22 +3,96 @@
//! This file provides API for compiler consumers.
use rustc_hir::def_id::LocalDefId;
-use rustc_index::vec::IndexSlice;
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_middle::mir::Body;
-use rustc_middle::ty::{self, TyCtxt};
+use rustc_index::{IndexSlice, IndexVec};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::mir::{Body, Promoted};
+use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::ty::TyCtxt;
+use std::rc::Rc;
+
+use crate::borrow_set::BorrowSet;
pub use super::{
+ constraints::OutlivesConstraint,
+ dataflow::{calculate_borrows_out_of_scope_at_location, BorrowIndex, Borrows},
facts::{AllFacts as PoloniusInput, RustcFacts},
location::{LocationTable, RichLocation},
nll::PoloniusOutput,
- BodyWithBorrowckFacts,
+ place_ext::PlaceExt,
+ places_conflict::{places_conflict, PlaceConflictBias},
+ region_infer::RegionInferenceContext,
};
-/// This function computes Polonius facts for the given body. It makes a copy of
-/// the body because it needs to regenerate the region identifiers. This function
-/// should never be invoked during a typical compilation session due to performance
-/// issues with Polonius.
+/// Options determining the output behavior of [`get_body_with_borrowck_facts`].
+///
+/// If executing under `-Z polonius` the choice here has no effect, and everything as if
+/// [`PoloniusOutputFacts`](ConsumerOptions::PoloniusOutputFacts) had been selected
+/// will be retrieved.
+#[derive(Debug, Copy, Clone)]
+pub enum ConsumerOptions {
+ /// Retrieve the [`Body`] along with the [`BorrowSet`](super::borrow_set::BorrowSet)
+ /// and [`RegionInferenceContext`]. If you would like the body only, use
+ /// [`TyCtxt::mir_promoted`].
+ ///
+ /// These can be used in conjunction with [`calculate_borrows_out_of_scope_at_location`].
+ RegionInferenceContext,
+ /// The recommended option. Retrieves the maximal amount of information
+ /// without significant slowdowns.
+ ///
+ /// Implies [`RegionInferenceContext`](ConsumerOptions::RegionInferenceContext),
+ /// and additionally retrieve the [`LocationTable`] and [`PoloniusInput`] that
+ /// would be given to Polonius. Critically, this does not run Polonius, which
+ /// one may want to avoid due to performance issues on large bodies.
+ PoloniusInputFacts,
+ /// Implies [`PoloniusInputFacts`](ConsumerOptions::PoloniusInputFacts),
+ /// and additionally runs Polonius to calculate the [`PoloniusOutput`].
+ PoloniusOutputFacts,
+}
+
+impl ConsumerOptions {
+ /// Should the Polonius input facts be computed?
+ pub(crate) fn polonius_input(&self) -> bool {
+ matches!(self, Self::PoloniusInputFacts | Self::PoloniusOutputFacts)
+ }
+ /// Should we run Polonius and collect the output facts?
+ pub(crate) fn polonius_output(&self) -> bool {
+ matches!(self, Self::PoloniusOutputFacts)
+ }
+}
+
+/// A `Body` with information computed by the borrow checker. This struct is
+/// intended to be consumed by compiler consumers.
+///
+/// We need to include the MIR body here because the region identifiers must
+/// match the ones in the Polonius facts.
+pub struct BodyWithBorrowckFacts<'tcx> {
+ /// A mir body that contains region identifiers.
+ pub body: Body<'tcx>,
+ /// The mir bodies of promoteds.
+ pub promoted: IndexVec<Promoted, Body<'tcx>>,
+ /// The set of borrows occurring in `body` with data about them.
+ pub borrow_set: Rc<BorrowSet<'tcx>>,
+ /// Context generated during borrowck, intended to be passed to
+ /// [`calculate_borrows_out_of_scope_at_location`].
+ pub region_inference_context: Rc<RegionInferenceContext<'tcx>>,
+ /// The table that maps Polonius points to locations in the table.
+ /// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
+ /// or [`ConsumerOptions::PoloniusOutputFacts`].
+ pub location_table: Option<LocationTable>,
+ /// Polonius input facts.
+ /// Populated when using [`ConsumerOptions::PoloniusInputFacts`]
+ /// or [`ConsumerOptions::PoloniusOutputFacts`].
+ pub input_facts: Option<Box<PoloniusInput>>,
+ /// Polonius output facts. Populated when using
+ /// [`ConsumerOptions::PoloniusOutputFacts`].
+ pub output_facts: Option<Rc<PoloniusOutput>>,
+}
+
+/// This function computes borrowck facts for the given body. The [`ConsumerOptions`]
+/// determine which facts are returned. This function makes a copy of the body because
+/// it needs to regenerate the region identifiers. It should never be invoked during a
+/// typical compilation session due to the unnecessary overhead of returning
+/// [`BodyWithBorrowckFacts`].
///
/// Note:
/// * This function will panic if the required body was already stolen. This
@@ -30,11 +104,12 @@ pub use super::{
/// * Polonius is highly unstable, so expect regular changes in its signature or other details.
pub fn get_body_with_borrowck_facts(
tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
+ options: ConsumerOptions,
) -> BodyWithBorrowckFacts<'_> {
let (input_body, promoted) = tcx.mir_promoted(def);
- let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def.did)).build();
+ let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(def)).build();
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexSlice<_, _> = &promoted.borrow();
- *super::do_mir_borrowck(&infcx, input_body, promoted, true).1.unwrap()
+ *super::do_mir_borrowck(&infcx, input_body, promoted, Some(options)).1.unwrap()
}
diff --git a/compiler/rustc_borrowck/src/dataflow.rs b/compiler/rustc_borrowck/src/dataflow.rs
index 94939c7e4..2daa82aef 100644
--- a/compiler/rustc_borrowck/src/dataflow.rs
+++ b/compiler/rustc_borrowck/src/dataflow.rs
@@ -156,10 +156,10 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
&mut self,
borrow_index: BorrowIndex,
borrow_region: RegionVid,
- location: Location,
+ first_location: Location,
) {
// We visit one BB at a time. The complication is that we may start in the
- // middle of the first BB visited (the one containing `location`), in which
+ // middle of the first BB visited (the one containing `first_location`), in which
// case we may have to later on process the first part of that BB if there
// is a path back to its start.
@@ -168,61 +168,58 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
// `visited` once they are added to `stack`, before they are actually
// processed, because this avoids the need to look them up again on
// completion.
- self.visited.insert(location.block);
+ self.visited.insert(first_location.block);
- let mut first_lo = location.statement_index;
- let first_hi = self.body[location.block].statements.len();
+ let first_block = first_location.block;
+ let mut first_lo = first_location.statement_index;
+ let first_hi = self.body[first_block].statements.len();
- self.visit_stack.push(StackEntry { bb: location.block, lo: first_lo, hi: first_hi });
+ self.visit_stack.push(StackEntry { bb: first_block, lo: first_lo, hi: first_hi });
- while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
- // If we process the first part of the first basic block (i.e. we encounter that block
- // for the second time), we no longer have to visit its successors again.
- let mut finished_early = bb == location.block && hi != first_hi;
- for i in lo..=hi {
- let location = Location { block: bb, statement_index: i };
+ 'preorder: while let Some(StackEntry { bb, lo, hi }) = self.visit_stack.pop() {
+ if let Some(kill_stmt) =
+ self.regioncx.first_non_contained_inclusive(borrow_region, bb, lo, hi)
+ {
+ let kill_location = Location { block: bb, statement_index: kill_stmt };
// If region does not contain a point at the location, then add to list and skip
// successor locations.
- if !self.regioncx.region_contains(borrow_region, location) {
- debug!("borrow {:?} gets killed at {:?}", borrow_index, location);
- self.borrows_out_of_scope_at_location
- .entry(location)
- .or_default()
- .push(borrow_index);
- finished_early = true;
- break;
- }
+ debug!("borrow {:?} gets killed at {:?}", borrow_index, kill_location);
+ self.borrows_out_of_scope_at_location
+ .entry(kill_location)
+ .or_default()
+ .push(borrow_index);
+ continue 'preorder;
}
- if !finished_early {
- // Add successor BBs to the work list, if necessary.
- let bb_data = &self.body[bb];
- debug_assert!(hi == bb_data.statements.len());
- for succ_bb in bb_data.terminator().successors() {
- if !self.visited.insert(succ_bb) {
- if succ_bb == location.block && first_lo > 0 {
- // `succ_bb` has been seen before. If it wasn't
- // fully processed, add its first part to `stack`
- // for processing.
- self.visit_stack.push(StackEntry {
- bb: succ_bb,
- lo: 0,
- hi: first_lo - 1,
- });
-
- // And update this entry with 0, to represent the
- // whole BB being processed.
- first_lo = 0;
- }
- } else {
- // succ_bb hasn't been seen before. Add it to
- // `stack` for processing.
- self.visit_stack.push(StackEntry {
- bb: succ_bb,
- lo: 0,
- hi: self.body[succ_bb].statements.len(),
- });
+ // If we process the first part of the first basic block (i.e. we encounter that block
+ // for the second time), we no longer have to visit its successors again.
+ if bb == first_block && hi != first_hi {
+ continue;
+ }
+
+ // Add successor BBs to the work list, if necessary.
+ let bb_data = &self.body[bb];
+ debug_assert!(hi == bb_data.statements.len());
+ for succ_bb in bb_data.terminator().successors() {
+ if !self.visited.insert(succ_bb) {
+ if succ_bb == first_block && first_lo > 0 {
+ // `succ_bb` has been seen before. If it wasn't
+ // fully processed, add its first part to `stack`
+ // for processing.
+ self.visit_stack.push(StackEntry { bb: succ_bb, lo: 0, hi: first_lo - 1 });
+
+ // And update this entry with 0, to represent the
+ // whole BB being processed.
+ first_lo = 0;
}
+ } else {
+ // succ_bb hasn't been seen before. Add it to
+ // `stack` for processing.
+ self.visit_stack.push(StackEntry {
+ bb: succ_bb,
+ lo: 0,
+ hi: self.body[succ_bb].statements.len(),
+ });
}
}
}
@@ -231,27 +228,32 @@ impl<'tcx> OutOfScopePrecomputer<'_, 'tcx> {
}
}
+pub fn calculate_borrows_out_of_scope_at_location<'tcx>(
+ body: &Body<'tcx>,
+ regioncx: &RegionInferenceContext<'tcx>,
+ borrow_set: &BorrowSet<'tcx>,
+) -> FxIndexMap<Location, Vec<BorrowIndex>> {
+ let mut prec = OutOfScopePrecomputer::new(body, regioncx);
+ for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
+ let borrow_region = borrow_data.region;
+ let location = borrow_data.reserve_location;
+
+ prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location);
+ }
+
+ prec.borrows_out_of_scope_at_location
+}
+
impl<'a, 'tcx> Borrows<'a, 'tcx> {
- pub(crate) fn new(
+ pub fn new(
tcx: TyCtxt<'tcx>,
body: &'a Body<'tcx>,
nonlexical_regioncx: &'a RegionInferenceContext<'tcx>,
borrow_set: &'a BorrowSet<'tcx>,
) -> Self {
- let mut prec = OutOfScopePrecomputer::new(body, nonlexical_regioncx);
- for (borrow_index, borrow_data) in borrow_set.iter_enumerated() {
- let borrow_region = borrow_data.region;
- let location = borrow_data.reserve_location;
-
- prec.precompute_borrows_out_of_scope(borrow_index, borrow_region, location);
- }
-
- Borrows {
- tcx,
- body,
- borrow_set,
- borrows_out_of_scope_at_location: prec.borrows_out_of_scope_at_location,
- }
+ let borrows_out_of_scope_at_location =
+ calculate_borrows_out_of_scope_at_location(body, nonlexical_regioncx, borrow_set);
+ Borrows { tcx, body, borrow_set, borrows_out_of_scope_at_location }
}
pub fn location(&self, idx: BorrowIndex) -> &Location {
@@ -328,7 +330,7 @@ impl<'tcx> rustc_mir_dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> {
fn bottom_value(&self, _: &mir::Body<'tcx>) -> Self::Domain {
// bottom = nothing is reserved or activated yet;
- BitSet::new_empty(self.borrow_set.len() * 2)
+ BitSet::new_empty(self.borrow_set.len())
}
fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) {
diff --git a/compiler/rustc_borrowck/src/def_use.rs b/compiler/rustc_borrowck/src/def_use.rs
index 6deb4e361..b719a610e 100644
--- a/compiler/rustc_borrowck/src/def_use.rs
+++ b/compiler/rustc_borrowck/src/def_use.rs
@@ -51,12 +51,16 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
PlaceContext::NonMutatingUse(NonMutatingUseContext::SharedBorrow) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::ShallowBorrow) |
+ // `PlaceMention` and `AscribeUserType` both evaluate the place, which must not
+ // contain dangling references.
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention) |
+ PlaceContext::NonUse(NonUseContext::AscribeUserTy(_)) |
+
PlaceContext::MutatingUse(MutatingUseContext::AddressOf) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Inspect) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) |
PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) |
- PlaceContext::NonUse(NonUseContext::AscribeUserTy) |
PlaceContext::MutatingUse(MutatingUseContext::Retag) =>
Some(DefUse::Use),
@@ -71,8 +75,6 @@ pub fn categorize(context: PlaceContext) -> Option<DefUse> {
PlaceContext::MutatingUse(MutatingUseContext::Drop) =>
Some(DefUse::Drop),
- // This statement exists to help unsafeck. It does not require the place to be live.
- PlaceContext::NonUse(NonUseContext::PlaceMention) => None,
// Debug info is neither def nor use.
PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None,
diff --git a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
index 84f75caa6..f41795d60 100644
--- a/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/bound_region_errors.rs
@@ -128,7 +128,7 @@ impl<'tcx> ToUniverseInfo<'tcx>
}
}
-impl<'tcx, F, G> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F, G>> {
+impl<'tcx, F> ToUniverseInfo<'tcx> for Canonical<'tcx, type_op::custom::CustomTypeOp<F>> {
fn to_universe_info(self, _base_universe: ty::UniverseIndex) -> UniverseInfo<'tcx> {
// We can't rerun custom type ops.
UniverseInfo::other()
diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
index 75a3dd0c0..15d73ed73 100644
--- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs
@@ -1,5 +1,6 @@
+use std::iter;
+
use either::Either;
-use rustc_const_eval::util::CallKind;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::{
@@ -9,8 +10,8 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::{walk_block, walk_expr, Visitor};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, LangItem};
-use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::ObligationCause;
+use rustc_middle::hir::nested_filter::OnlyBodies;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
self, AggregateKind, BindingForm, BorrowKind, ClearCrossCrate, ConstraintCategory,
@@ -18,20 +19,19 @@ use rustc_middle::mir::{
ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, VarBindingForm,
};
use rustc_middle::ty::{self, suggest_constraining_type_params, PredicateKind, Ty};
+use rustc_middle::util::CallKind;
use rustc_mir_dataflow::move_paths::{InitKind, MoveOutIndex, MovePathIndex};
use rustc_span::def_id::LocalDefId;
use rustc_span::hygiene::DesugaringKind;
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::{BytePos, Span, Symbol};
use rustc_trait_selection::infer::InferCtxtExt;
use rustc_trait_selection::traits::ObligationCtxt;
use crate::borrow_set::TwoPhaseActivation;
use crate::borrowck_errors;
-
use crate::diagnostics::conflict_errors::StorageDeadOrDrop::LocalStorageDead;
-use crate::diagnostics::find_all_local_uses;
-use crate::diagnostics::mutability_errors::mut_borrow_of_mutable_ref;
+use crate::diagnostics::{find_all_local_uses, CapturedMessageOpt};
use crate::{
borrow_set::BorrowData, diagnostics::Instance, prefixes::IsPrefixOf,
InitializationRequiringAction, MirBorrowckCtxt, PrefixSet, WriteKind,
@@ -158,7 +158,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
} else if reinits > 1 {
err.span_note(
MultiSpan::from_spans(reinit_spans),
- &if reinits <= 3 {
+ if reinits <= 3 {
format!("these {reinits} reinitializations might get skipped")
} else {
format!(
@@ -183,13 +183,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let move_spans = self.move_spans(moved_place.as_ref(), move_out.source);
let move_span = move_spans.args_or_use();
- let move_msg = if move_spans.for_closure() { " into closure" } else { "" };
+ let is_move_msg = move_spans.for_closure();
- let loop_message = if location == move_out.source || move_site.traversed_back_edge {
- ", in previous iteration of loop"
- } else {
- ""
- };
+ let is_loop_message = location == move_out.source || move_site.traversed_back_edge;
if location == move_out.source {
is_loop_move = true;
@@ -206,17 +202,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
}
+ let msg_opt = CapturedMessageOpt {
+ is_partial_move,
+ is_loop_message,
+ is_move_msg,
+ is_loop_move,
+ maybe_reinitialized_locations_is_empty: maybe_reinitialized_locations
+ .is_empty(),
+ };
self.explain_captures(
&mut err,
span,
move_span,
move_spans,
*moved_place,
- partially_str,
- loop_message,
- move_msg,
- is_loop_move,
- maybe_reinitialized_locations.is_empty(),
+ msg_opt,
);
}
seen_spans.insert(move_span);
@@ -253,7 +253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// We have a `&mut` ref, we need to reborrow on each iteration (#62112).
err.span_suggestion_verbose(
span.shrink_to_lo(),
- &format!(
+ format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place)
.map(|n| format!("`{n}`"))
@@ -282,12 +282,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
if needs_note {
- let span = if let Some(local) = place.as_local() {
- Some(self.body.local_decls[local].source_info.span)
+ if let Some(local) = place.as_local() {
+ let span = self.body.local_decls[local].source_info.span;
+ err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+ is_partial_move,
+ ty,
+ place: &note_msg,
+ span,
+ });
} else {
- None
+ err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Note {
+ is_partial_move,
+ ty,
+ place: &note_msg,
+ });
};
- self.note_type_does_not_implement_copy(&mut err, &note_msg, ty, span, partial_str);
}
if let UseSpans::FnSelfUse {
@@ -295,7 +304,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
..
} = use_spans
{
- err.note(&format!(
+ err.note(format!(
"{} occurs due to deref coercion to `{deref_target_ty}`",
desired_action.as_noun(),
));
@@ -577,7 +586,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// _ => {} // We don't want to point to this.
// };
// ```
- err.span_label(sp, &label);
+ err.span_label(sp, label);
shown = true;
}
}
@@ -633,11 +642,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let Some(default_trait) = tcx.get_diagnostic_item(sym::Default) else {
return false;
};
- // Regions are already solved, so we must use a fresh InferCtxt,
- // but the type has region variables, so erase those.
- tcx.infer_ctxt()
- .build()
- .type_implements_trait(default_trait, [tcx.erase_regions(ty)], param_env)
+ self.infcx
+ .type_implements_trait(default_trait, [ty], param_env)
.must_apply_modulo_regions()
};
@@ -696,7 +702,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.copied()
.find_map(find_fn_kind_from_did),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => tcx
- .bound_explicit_item_bounds(def_id)
+ .explicit_item_bounds(def_id)
.subst_iter_copied(tcx, substs)
.find_map(find_fn_kind_from_did),
ty::Closure(_, substs) => match substs.as_closure().kind() {
@@ -730,13 +736,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
fn suggest_cloning(&self, err: &mut Diagnostic, ty: Ty<'tcx>, span: Span) {
let tcx = self.infcx.tcx;
// Try to find predicates on *generic params* that would allow copying `ty`
- let infcx = tcx.infer_ctxt().build();
-
if let Some(clone_trait_def) = tcx.lang_items().clone_trait()
- && infcx
+ && self.infcx
.type_implements_trait(
clone_trait_def,
- [tcx.erase_regions(ty)],
+ [ty],
self.param_env,
)
.must_apply_modulo_regions()
@@ -760,12 +764,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
.and_then(|def_id| tcx.hir().get_generics(def_id))
else { return; };
// Try to find predicates on *generic params* that would allow copying `ty`
- let infcx = tcx.infer_ctxt().build();
- let ocx = ObligationCtxt::new(&infcx);
+ let ocx = ObligationCtxt::new(&self.infcx);
let copy_did = tcx.require_lang_item(LangItem::Copy, Some(span));
let cause = ObligationCause::misc(span, self.mir_def_id());
- ocx.register_bound(cause, self.param_env, infcx.tcx.erase_regions(ty), copy_did);
+ ocx.register_bound(cause, self.param_env, ty, copy_did);
let errors = ocx.select_all_or_error();
// Only emit suggestion if all required predicates are on generic
@@ -827,11 +830,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
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()),
- "moved",
- );
+ move_spans.var_subdiag(None, &mut err, None, |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => MoveUseInGenerator { var_span },
+ None => MoveUseInClosure { var_span },
+ }
+ });
self.explain_why_borrow_contains_point(location, borrow, None)
.add_explanation_to_diagnostic(
@@ -868,13 +873,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
borrow_span,
&self.describe_any_place(borrow.borrowed_place.as_ref()),
);
- borrow_spans.var_subdiag(&mut err, Some(borrow.kind), |kind, var_span| {
+ borrow_spans.var_subdiag(None, &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 },
+ Some(_) => {
+ BorrowUsePlaceGenerator { place: desc_place, var_span, is_single_var: true }
+ }
+ None => BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: true },
}
});
@@ -946,7 +953,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
&msg_borrow,
None,
);
- self.suggest_binding_for_closure_capture_self(
+ self.suggest_binding_for_closure_capture_self(&mut err, &issued_spans);
+ self.suggest_using_closure_argument_instead_of_capture(
&mut err,
issued_borrow.borrowed_place,
&issued_spans,
@@ -969,6 +977,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
place,
issued_borrow.borrowed_place,
);
+ self.suggest_using_closure_argument_instead_of_capture(
+ &mut err,
+ issued_borrow.borrowed_place,
+ &issued_spans,
+ );
err
}
@@ -988,16 +1001,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
immutable_section_description,
"mutably borrow",
);
- borrow_spans.var_span_label(
+ borrow_spans.var_subdiag(
+ None,
&mut err,
- format!(
- "borrow occurs due to use of {}{}",
- desc_place,
- borrow_spans.describe(),
- ),
- "immutable",
+ Some(BorrowKind::Unique),
+ |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => BorrowUsePlaceGenerator {
+ place: desc_place,
+ var_span,
+ is_single_var: true,
+ },
+ None => BorrowUsePlaceClosure {
+ place: desc_place,
+ var_span,
+ is_single_var: true,
+ },
+ }
+ },
);
-
return err;
} else {
first_borrow_desc = "immutable ";
@@ -1070,37 +1093,53 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
};
if issued_spans == borrow_spans {
- borrow_spans.var_span_label(
- &mut err,
- format!("borrows occur due to use of {}{}", desc_place, borrow_spans.describe(),),
- gen_borrow_kind.describe_mutability(),
- );
+ borrow_spans.var_subdiag(None, &mut err, Some(gen_borrow_kind), |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => BorrowUsePlaceGenerator {
+ place: desc_place,
+ var_span,
+ is_single_var: false,
+ },
+ None => {
+ BorrowUsePlaceClosure { place: desc_place, var_span, is_single_var: false }
+ }
+ }
+ });
} else {
- let borrow_place = &issued_borrow.borrowed_place;
- let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
- issued_spans.var_span_label(
+ issued_spans.var_subdiag(
+ Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
&mut err,
- format!(
- "first borrow occurs due to use of {}{}",
- borrow_place_desc,
- issued_spans.describe(),
- ),
- issued_borrow.kind.describe_mutability(),
+ Some(issued_borrow.kind),
+ |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ let borrow_place = &issued_borrow.borrowed_place;
+ let borrow_place_desc = self.describe_any_place(borrow_place.as_ref());
+ match kind {
+ Some(_) => {
+ FirstBorrowUsePlaceGenerator { place: borrow_place_desc, var_span }
+ }
+ None => FirstBorrowUsePlaceClosure { place: borrow_place_desc, var_span },
+ }
+ },
);
- borrow_spans.var_span_label(
+ borrow_spans.var_subdiag(
+ Some(&self.infcx.tcx.sess.parse_sess.span_diagnostic),
&mut err,
- format!(
- "second borrow occurs due to use of {}{}",
- desc_place,
- borrow_spans.describe(),
- ),
- gen_borrow_kind.describe_mutability(),
+ Some(gen_borrow_kind),
+ |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => SecondBorrowUsePlaceGenerator { place: desc_place, var_span },
+ None => SecondBorrowUsePlaceClosure { place: desc_place, var_span },
+ }
+ },
);
}
if union_type_name != "" {
- err.note(&format!(
+ err.note(format!(
"{} is a field of the union `{}`, so it overlaps the field {}",
msg_place, union_type_name, msg_borrow,
));
@@ -1199,14 +1238,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
err.span_help(
inner_call_span,
- &format!(
+ format!(
"try adding a local storing this{}...",
if use_span.is_some() { "" } else { " argument" }
),
);
err.span_help(
outer_call_span,
- &format!(
+ format!(
"...and then using that local {}",
if use_span.is_some() { "here" } else { "as the argument to this call" }
),
@@ -1229,22 +1268,160 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- fn suggest_binding_for_closure_capture_self(
+ /// Suggest using closure argument instead of capture.
+ ///
+ /// For example:
+ /// ```ignore (illustrative)
+ /// struct S;
+ ///
+ /// impl S {
+ /// fn call(&mut self, f: impl Fn(&mut Self)) { /* ... */ }
+ /// fn x(&self) {}
+ /// }
+ ///
+ /// let mut v = S;
+ /// v.call(|this: &mut S| v.x());
+ /// // ^\ ^-- help: try using the closure argument: `this`
+ /// // *-- error: cannot borrow `v` as mutable because it is also borrowed as immutable
+ /// ```
+ fn suggest_using_closure_argument_instead_of_capture(
&self,
err: &mut Diagnostic,
borrowed_place: Place<'tcx>,
issued_spans: &UseSpans<'tcx>,
) {
- let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
- let hir = self.infcx.tcx.hir();
+ let &UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+ let tcx = self.infcx.tcx;
+ let hir = tcx.hir();
- // check whether the borrowed place is capturing `self` by mut reference
+ // Get the type of the local that we are trying to borrow
let local = borrowed_place.local;
- let Some(_) = self
- .body
- .local_decls
- .get(local)
- .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) else { return };
+ let local_ty = self.body.local_decls[local].ty;
+
+ // Get the body the error happens in
+ let Some(body_id) = hir.get(self.mir_hir_id()).body_id() else { return };
+
+ let body_expr = hir.body(body_id).value;
+
+ struct ClosureFinder<'hir> {
+ hir: rustc_middle::hir::map::Map<'hir>,
+ borrow_span: Span,
+ res: Option<(&'hir hir::Expr<'hir>, &'hir hir::Closure<'hir>)>,
+ /// The path expression with the `borrow_span` span
+ error_path: Option<(&'hir hir::Expr<'hir>, &'hir hir::QPath<'hir>)>,
+ }
+ impl<'hir> Visitor<'hir> for ClosureFinder<'hir> {
+ type NestedFilter = OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.hir
+ }
+
+ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+ if let hir::ExprKind::Path(qpath) = &ex.kind
+ && ex.span == self.borrow_span
+ {
+ self.error_path = Some((ex, qpath));
+ }
+
+ if let hir::ExprKind::Closure(closure) = ex.kind
+ && ex.span.contains(self.borrow_span)
+ // To support cases like `|| { v.call(|this| v.get()) }`
+ // FIXME: actually support such cases (need to figure out how to move from the capture place to original local)
+ && self.res.as_ref().map_or(true, |(prev_res, _)| prev_res.span.contains(ex.span))
+ {
+ self.res = Some((ex, closure));
+ }
+
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+
+ // Find the closure that most tightly wraps `capture_kind_span`
+ let mut finder =
+ ClosureFinder { hir, borrow_span: capture_kind_span, res: None, error_path: None };
+ finder.visit_expr(body_expr);
+ let Some((closure_expr, closure)) = finder.res else { return };
+
+ let typeck_results = tcx.typeck(self.mir_def_id());
+
+ // Check that the parent of the closure is a method call,
+ // with receiver matching with local's type (modulo refs)
+ let parent = hir.parent_id(closure_expr.hir_id);
+ if let hir::Node::Expr(parent) = hir.get(parent) {
+ if let hir::ExprKind::MethodCall(_, recv, ..) = parent.kind {
+ let recv_ty = typeck_results.expr_ty(recv);
+
+ if recv_ty.peel_refs() != local_ty {
+ return;
+ }
+ }
+ }
+
+ // Get closure's arguments
+ let ty::Closure(_, substs) = typeck_results.expr_ty(closure_expr).kind() else { /* hir::Closure can be a generator too */ return };
+ let sig = substs.as_closure().sig();
+ let tupled_params =
+ tcx.erase_late_bound_regions(sig.inputs().iter().next().unwrap().map_bound(|&b| b));
+ let ty::Tuple(params) = tupled_params.kind() else { return };
+
+ // Find the first argument with a matching type, get its name
+ let Some((_, this_name)) = params
+ .iter()
+ .zip(hir.body_param_names(closure.body))
+ .find(|(param_ty, name)|{
+ // FIXME: also support deref for stuff like `Rc` arguments
+ param_ty.peel_refs() == local_ty && name != &Ident::empty()
+ })
+ else { return };
+
+ let spans;
+ if let Some((_path_expr, qpath)) = finder.error_path
+ && let hir::QPath::Resolved(_, path) = qpath
+ && let hir::def::Res::Local(local_id) = path.res
+ {
+ // Find all references to the problematic variable in this closure body
+
+ struct VariableUseFinder {
+ local_id: hir::HirId,
+ spans: Vec<Span>,
+ }
+ impl<'hir> Visitor<'hir> for VariableUseFinder {
+ fn visit_expr(&mut self, ex: &'hir hir::Expr<'hir>) {
+ if let hir::ExprKind::Path(qpath) = &ex.kind
+ && let hir::QPath::Resolved(_, path) = qpath
+ && let hir::def::Res::Local(local_id) = path.res
+ && local_id == self.local_id
+ {
+ self.spans.push(ex.span);
+ }
+
+ hir::intravisit::walk_expr(self, ex);
+ }
+ }
+
+ let mut finder = VariableUseFinder { local_id, spans: Vec::new() };
+ finder.visit_expr(hir.body(closure.body).value);
+
+ spans = finder.spans;
+ } else {
+ spans = vec![capture_kind_span];
+ }
+
+ err.multipart_suggestion(
+ "try using the closure argument",
+ iter::zip(spans, iter::repeat(this_name.to_string())).collect(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+
+ fn suggest_binding_for_closure_capture_self(
+ &self,
+ err: &mut Diagnostic,
+ issued_spans: &UseSpans<'tcx>,
+ ) {
+ let UseSpans::ClosureUse { capture_kind_span, .. } = issued_spans else { return };
+ let hir = self.infcx.tcx.hir();
struct ExpressionFinder<'hir> {
capture_span: Span,
@@ -1458,34 +1635,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
})
}
- /// Reports StorageDeadOrDrop of `place` conflicts with `borrow`.
- ///
- /// Depending on the origin of the StorageDeadOrDrop, this may be
- /// reported as either a drop or an illegal mutation of a borrowed value.
- /// The latter is preferred when the this is a drop triggered by a
- /// reassignment, as it's more user friendly to report a problem with the
- /// explicit assignment than the implicit drop.
- #[instrument(level = "debug", skip(self))]
- pub(crate) fn report_storage_dead_or_drop_of_borrowed(
- &mut self,
- location: Location,
- place_span: (Place<'tcx>, Span),
- borrow: &BorrowData<'tcx>,
- ) {
- // It's sufficient to check the last desugaring as Replace is the last
- // one to be applied.
- if let Some(DesugaringKind::Replace) = place_span.1.desugaring_kind() {
- self.report_illegal_mutation_of_borrowed(location, place_span, borrow)
- } else {
- self.report_borrowed_value_does_not_live_long_enough(
- location,
- borrow,
- place_span,
- Some(WriteKind::StorageDeadOrDrop),
- )
- }
- }
-
/// This means that some data referenced by `borrow` needs to live
/// past the point where the StorageDeadOrDrop of `place` occurs.
/// This is usually interpreted as meaning that `place` has too
@@ -1731,9 +1880,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
err.span_label(borrow_span, "borrowed value does not live long enough");
err.span_label(drop_span, format!("`{}` dropped here while still borrowed", name));
- let within = if borrow_spans.for_generator() { " by generator" } else { "" };
-
- borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
+ borrow_spans.args_subdiag(&mut err, |args_span| {
+ crate::session_diagnostics::CaptureArgLabel::Capture {
+ is_within: borrow_spans.for_generator(),
+ args_span,
+ }
+ });
explanation.add_explanation_to_diagnostic(
self.infcx.tcx,
@@ -1947,9 +2099,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
None,
);
- let within = if borrow_spans.for_generator() { " by generator" } else { "" };
-
- borrow_spans.args_span_label(&mut err, format!("value captured here{}", within));
+ borrow_spans.args_subdiag(&mut err, |args_span| {
+ crate::session_diagnostics::CaptureArgLabel::Capture {
+ is_within: borrow_spans.for_generator(),
+ args_span,
+ }
+ });
err
}
@@ -2029,7 +2184,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let tcx = self.infcx.tcx;
let return_ty = self.regioncx.universal_regions().unnormalized_output_ty;
- let return_ty = tcx.erase_regions(return_ty);
// to avoid panics
if let Some(iter_trait) = tcx.get_diagnostic_item(sym::Iterator)
@@ -2099,7 +2253,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
err.span_suggestion_verbose(
sugg_span,
- &format!(
+ format!(
"to force the {} to take ownership of {} (and any \
other referenced variables), use the `move` keyword",
kind, captured_var
@@ -2111,7 +2265,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
match category {
ConstraintCategory::Return(_) | ConstraintCategory::OpaqueType => {
let msg = format!("{} is returned here", kind);
- err.span_note(constraint_span, &msg);
+ err.span_note(constraint_span, msg);
}
ConstraintCategory::CallArgument(_) => {
fr_name.highlight_region_name(&mut err);
@@ -2122,7 +2276,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
);
} else {
let msg = format!("{scope} requires argument type to outlive `{fr_name}`");
- err.span_note(constraint_span, &msg);
+ err.span_note(constraint_span, msg);
}
}
_ => bug!(
@@ -2382,11 +2536,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
section,
"assign",
);
- loan_spans.var_span_label(
- &mut err,
- format!("borrow occurs due to use{}", loan_spans.describe()),
- loan.kind.describe_mutability(),
- );
+
+ loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => BorrowUseInGenerator { var_span },
+ None => BorrowUseInClosure { var_span },
+ }
+ });
self.buffer_error(err);
@@ -2396,11 +2553,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
let mut err = self.cannot_assign_to_borrowed(span, loan_span, &descr_place);
- loan_spans.var_span_label(
- &mut err,
- format!("borrow occurs due to use{}", loan_spans.describe()),
- loan.kind.describe_mutability(),
- );
+ loan_spans.var_subdiag(None, &mut err, Some(loan.kind), |kind, var_span| {
+ use crate::session_diagnostics::CaptureVarCause::*;
+ match kind {
+ Some(_) => BorrowUseInGenerator { var_span },
+ None => BorrowUseInClosure { var_span },
+ }
+ });
self.explain_why_borrow_contains_point(location, loan, None).add_explanation_to_diagnostic(
self.infcx.tcx,
@@ -2424,7 +2583,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Some((method_did, method_substs)),
) = (
&self.body[loan.reserve_location.block].terminator,
- rustc_const_eval::util::find_self_call(
+ rustc_middle::util::find_self_call(
tcx,
self.body,
loan.assigned_place.local,
@@ -2439,7 +2598,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
});
if let Some(Ok(instance)) = deref_target {
let deref_target_ty = instance.ty(tcx, self.param_env);
- err.note(&format!(
+ err.note(format!(
"borrow occurs due to deref coercion to `{}`",
deref_target_ty
));
@@ -2993,7 +3152,7 @@ impl<'tcx> AnnotatedBorrowFnSignature<'tcx> {
diag.span_label(*return_span, format!("also has lifetime `{}`", region_name,));
- diag.help(&format!(
+ diag.help(format!(
"use data from the highlighted arguments which match the `{}` lifetime of \
the return type",
region_name,
diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
index 8860395e7..1d430a93a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
@@ -3,7 +3,7 @@
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::{
Body, CastKind, ConstraintCategory, FakeReadCause, Local, LocalInfo, Location, Operand, Place,
@@ -90,7 +90,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
{
err.span_label(
pat.span,
- &format!("binding `{ident}` declared here"),
+ format!("binding `{ident}` declared here"),
);
}
}
@@ -118,7 +118,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
let path_span = path_span.unwrap();
// path_span is only present in the case of closure capture
assert!(matches!(later_use_kind, LaterUseKind::ClosureCapture));
- if !borrow_span.map_or(false, |sp| sp.overlaps(var_or_use_span)) {
+ if !borrow_span.is_some_and(|sp| sp.overlaps(var_or_use_span)) {
let path_label = "used here by closure";
let capture_kind_label = message;
err.span_label(
@@ -224,12 +224,9 @@ impl<'tcx> BorrowExplanation<'tcx> {
if info.tail_result_is_ignored {
// #85581: If the first mutable borrow's scope contains
// the second borrow, this suggestion isn't helpful.
- if !multiple_borrow_span
- .map(|(old, new)| {
- old.to(info.span.shrink_to_hi()).contains(new)
- })
- .unwrap_or(false)
- {
+ if !multiple_borrow_span.is_some_and(|(old, new)| {
+ old.to(info.span.shrink_to_hi()).contains(new)
+ }) {
err.span_suggestion_verbose(
info.span.shrink_to_hi(),
"consider adding semicolon after the expression so its \
@@ -323,7 +320,7 @@ impl<'tcx> BorrowExplanation<'tcx> {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &msg,
+ msg,
format!(" + {suggestable_name}"),
Applicability::Unspecified,
);
diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs
index 110354a20..20370e4c6 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mod.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs
@@ -1,13 +1,16 @@
//! Borrow checker diagnostics.
+use crate::session_diagnostics::{
+ CaptureArgLabel, CaptureReasonLabel, CaptureReasonNote, CaptureReasonSuggest, CaptureVarCause,
+ CaptureVarKind, CaptureVarPathUseCause, OnClosureNote,
+};
use itertools::Itertools;
-use rustc_const_eval::util::{call_kind, CallDesugaringKind};
use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, Namespace};
use rustc_hir::GeneratorKind;
-use rustc_index::vec::IndexSlice;
-use rustc_infer::infer::{LateBoundRegionConversionTime, TyCtxtInferExt};
+use rustc_index::IndexSlice;
+use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::{
AggregateKind, Constant, FakeReadCause, Local, LocalInfo, LocalKind, Location, Operand, Place,
@@ -15,6 +18,7 @@ use rustc_middle::mir::{
};
use rustc_middle::ty::print::Print;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
+use rustc_middle::util::{call_kind, CallDesugaringKind};
use rustc_mir_dataflow::move_paths::{InitLocation, LookupResult};
use rustc_span::def_id::LocalDefId;
use rustc_span::{symbol::sym, Span, Symbol, DUMMY_SP};
@@ -45,7 +49,7 @@ pub(crate) use mutability_errors::AccessKind;
pub(crate) use outlives_suggestion::OutlivesSuggestionBuilder;
pub(crate) use region_errors::{ErrorConstraintInfo, RegionErrorKind, RegionErrors};
pub(crate) use region_name::{RegionName, RegionNameSource};
-pub(crate) use rustc_const_eval::util::CallKind;
+pub(crate) use rustc_middle::util::CallKind;
pub(super) struct DescribePlaceOpt {
pub including_downcast: bool,
@@ -117,13 +121,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Closure(did, _) = self.body.local_decls[closure].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
- diag.span_note(
- *span,
- &format!(
- "closure cannot be invoked more than once because it moves the \
- variable `{}` out of its environment",
- ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
- ),
+ diag.eager_subdiagnostic(
+ &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ OnClosureNote::InvokedTwice {
+ place_name: &ty::place_to_string_for_capture(
+ self.infcx.tcx,
+ hir_place,
+ ),
+ span: *span,
+ },
);
return true;
}
@@ -137,13 +143,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let ty::Closure(did, _) = self.body.local_decls[target].ty.kind() {
let did = did.expect_local();
if let Some((span, hir_place)) = self.infcx.tcx.closure_kind_origin(did) {
- diag.span_note(
- *span,
- &format!(
- "closure cannot be moved more than once as it is not `Copy` due to \
- moving the variable `{}` out of its environment",
- ty::place_to_string_for_capture(self.infcx.tcx, hir_place)
- ),
+ diag.eager_subdiagnostic(
+ &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ OnClosureNote::MovedTwice {
+ place_name: &ty::place_to_string_for_capture(self.infcx.tcx, hir_place),
+ span: *span,
+ },
);
return true;
}
@@ -380,25 +385,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
- /// Add a note that a type does not implement `Copy`
- pub(super) fn note_type_does_not_implement_copy(
- &self,
- err: &mut Diagnostic,
- place_desc: &str,
- ty: Ty<'tcx>,
- span: Option<Span>,
- move_prefix: &str,
- ) {
- let message = format!(
- "{move_prefix}move occurs because {place_desc} has type `{ty}`, which does not implement the `Copy` trait",
- );
- if let Some(span) = span {
- err.span_label(span, message);
- } else {
- err.note(&message);
- }
- }
-
pub(super) fn borrowed_content_source(
&self,
deref_base: PlaceRef<'tcx>,
@@ -582,9 +568,13 @@ impl UseSpans<'_> {
}
/// Add a span label to the arguments of the closure, if it exists.
- pub(super) fn args_span_label(self, err: &mut Diagnostic, message: impl Into<String>) {
+ pub(super) fn args_subdiag(
+ self,
+ err: &mut Diagnostic,
+ f: impl FnOnce(Span) -> CaptureArgLabel,
+ ) {
if let UseSpans::ClosureUse { args_span, .. } = self {
- err.span_label(args_span, message);
+ err.subdiagnostic(f(args_span));
}
}
@@ -595,8 +585,8 @@ impl UseSpans<'_> {
err: &mut Diagnostic,
action: crate::InitializationRequiringAction,
) {
- use crate::session_diagnostics::CaptureVarPathUseCause::*;
use crate::InitializationRequiringAction::*;
+ use CaptureVarPathUseCause::*;
if let UseSpans::ClosureUse { generator_kind, path_span, .. } = self {
match generator_kind {
Some(_) => {
@@ -619,34 +609,14 @@ impl UseSpans<'_> {
}
}
- /// Add a span label to the use of the captured variable, if it exists.
- pub(super) fn var_span_label(
- self,
- err: &mut Diagnostic,
- message: impl Into<String>,
- kind_desc: impl Into<String>,
- ) {
- if let UseSpans::ClosureUse { capture_kind_span, path_span, .. } = self {
- if capture_kind_span == path_span {
- err.span_label(capture_kind_span, message);
- } else {
- let capture_kind_label =
- format!("capture is {} because of use here", kind_desc.into());
- let path_label = message;
- err.span_label(capture_kind_span, capture_kind_label);
- err.span_label(path_span, path_label);
- }
- }
- }
-
/// Add a subdiagnostic to the use of the captured variable, if it exists.
pub(super) fn var_subdiag(
self,
+ handler: Option<&rustc_errors::Handler>,
err: &mut Diagnostic,
kind: Option<rustc_middle::mir::BorrowKind>,
- f: impl Fn(Option<GeneratorKind>, Span) -> crate::session_diagnostics::CaptureVarCause,
+ f: impl FnOnce(Option<GeneratorKind>, Span) -> 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 {
@@ -654,17 +624,21 @@ impl UseSpans<'_> {
rustc_middle::mir::BorrowKind::Shared
| rustc_middle::mir::BorrowKind::Shallow
| rustc_middle::mir::BorrowKind::Unique => {
- Immute { kind_span: capture_kind_span }
+ CaptureVarKind::Immut { kind_span: capture_kind_span }
}
rustc_middle::mir::BorrowKind::Mut { .. } => {
- Mut { kind_span: capture_kind_span }
+ CaptureVarKind::Mut { kind_span: capture_kind_span }
}
},
- None => Move { kind_span: capture_kind_span },
+ None => CaptureVarKind::Move { kind_span: capture_kind_span },
});
};
- err.subdiagnostic(f(generator_kind, path_span));
+ let diag = f(generator_kind, path_span);
+ match handler {
+ Some(hd) => err.eager_subdiagnostic(hd, diag),
+ None => err.subdiagnostic(diag),
+ };
}
}
@@ -684,20 +658,6 @@ impl UseSpans<'_> {
}
}
- /// Describe the span associated with a use of a place.
- pub(super) fn describe(&self) -> &str {
- match *self {
- UseSpans::ClosureUse { generator_kind, .. } => {
- if generator_kind.is_some() {
- " in generator"
- } else {
- " in closure"
- }
- }
- _ => "",
- }
- }
-
pub(super) fn or_else<F>(self, if_other: F) -> Self
where
F: FnOnce() -> Self,
@@ -788,6 +748,15 @@ impl<'tcx> BorrowedContentSource<'tcx> {
}
}
+///helper struct for explain_captures()
+struct CapturedMessageOpt {
+ is_partial_move: bool,
+ is_loop_message: bool,
+ is_move_msg: bool,
+ is_loop_move: bool,
+ maybe_reinitialized_locations_is_empty: bool,
+}
+
impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
/// Finds the spans associated to a move or copy of move_place at location.
pub(super) fn move_spans(
@@ -874,7 +843,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}) = &self.body[location.block].terminator
{
let Some((method_did, method_substs)) =
- rustc_const_eval::util::find_self_call(
+ rustc_middle::util::find_self_call(
self.infcx.tcx,
&self.body,
target_temp,
@@ -1027,12 +996,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
move_span: Span,
move_spans: UseSpans<'tcx>,
moved_place: Place<'tcx>,
- partially_str: &str,
- loop_message: &str,
- move_msg: &str,
- is_loop_move: bool,
- maybe_reinitialized_locations_is_empty: bool,
+ msg_opt: CapturedMessageOpt,
) {
+ let CapturedMessageOpt {
+ is_partial_move: is_partial,
+ is_loop_message,
+ is_move_msg,
+ is_loop_move,
+ maybe_reinitialized_locations_is_empty,
+ } = msg_opt;
if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = move_spans {
let place_name = self
.describe_place(moved_place.as_ref())
@@ -1042,30 +1014,26 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
CallKind::FnCall { fn_trait_id, .. }
if Some(fn_trait_id) == self.infcx.tcx.lang_items().fn_once_trait() =>
{
- err.span_label(
+ err.subdiagnostic(CaptureReasonLabel::Call {
fn_call_span,
- &format!(
- "{place_name} {partially_str}moved due to this call{loop_message}",
- ),
- );
- err.span_note(
- var_span,
- "this value implements `FnOnce`, which causes it to be moved when called",
- );
+ place_name: &place_name,
+ is_partial,
+ is_loop_message,
+ });
+ err.subdiagnostic(CaptureReasonNote::FnOnceMoveInCall { var_span });
}
CallKind::Operator { self_arg, .. } => {
let self_arg = self_arg.unwrap();
- err.span_label(
+ err.subdiagnostic(CaptureReasonLabel::OperatorUse {
fn_call_span,
- &format!(
- "{place_name} {partially_str}moved due to usage in operator{loop_message}",
- ),
- );
+ place_name: &place_name,
+ is_partial,
+ is_loop_message,
+ });
if self.fn_self_span_reported.insert(fn_span) {
- err.span_note(
- self_arg.span,
- "calling this operator moves the left-hand side",
- );
+ err.subdiagnostic(CaptureReasonNote::LhsMoveByOperator {
+ span: self_arg.span,
+ });
}
}
CallKind::Normal { self_arg, desugaring, method_did, method_substs } => {
@@ -1074,35 +1042,27 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if let Some((CallDesugaringKind::ForLoopIntoIter, _)) = desugaring {
let ty = moved_place.ty(self.body, tcx).ty;
let suggest = match tcx.get_diagnostic_item(sym::IntoIterator) {
- Some(def_id) => {
- let infcx = self.infcx.tcx.infer_ctxt().build();
- type_known_to_meet_bound_modulo_regions(
- &infcx,
- self.param_env,
- tcx.mk_imm_ref(tcx.lifetimes.re_erased, tcx.erase_regions(ty)),
- def_id,
- )
- }
+ Some(def_id) => type_known_to_meet_bound_modulo_regions(
+ &self.infcx,
+ self.param_env,
+ tcx.mk_imm_ref(tcx.lifetimes.re_erased, ty),
+ def_id,
+ ),
_ => false,
};
if suggest {
- err.span_suggestion_verbose(
- move_span.shrink_to_lo(),
- &format!(
- "consider iterating over a slice of the `{ty}`'s content to \
- avoid moving into the `for` loop",
- ),
- "&",
- Applicability::MaybeIncorrect,
- );
+ err.subdiagnostic(CaptureReasonSuggest::IterateSlice {
+ ty,
+ span: move_span.shrink_to_lo(),
+ });
}
- err.span_label(
+ err.subdiagnostic(CaptureReasonLabel::ImplicitCall {
fn_call_span,
- &format!(
- "{place_name} {partially_str}moved due to this implicit call to `.into_iter()`{loop_message}",
- ),
- );
+ place_name: &place_name,
+ is_partial,
+ is_loop_message,
+ });
// If the moved place was a `&mut` ref, then we can
// suggest to reborrow it where it was moved, so it
// will still be valid by the time we get to the usage.
@@ -1113,7 +1073,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
if !is_loop_move {
err.span_suggestion_verbose(
move_span.shrink_to_lo(),
- &format!(
+ format!(
"consider creating a fresh reborrow of {} here",
self.describe_place(moved_place.as_ref())
.map(|n| format!("`{n}`"))
@@ -1125,44 +1085,49 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
}
} else {
- err.span_label(
- fn_call_span,
- &format!(
- "{place_name} {partially_str}moved due to this method call{loop_message}",
- ),
- );
-
- let infcx = tcx.infer_ctxt().build();
+ if let Some((CallDesugaringKind::Await, _)) = desugaring {
+ err.subdiagnostic(CaptureReasonLabel::Await {
+ fn_call_span,
+ place_name: &place_name,
+ is_partial,
+ is_loop_message,
+ });
+ } else {
+ err.subdiagnostic(CaptureReasonLabel::MethodCall {
+ fn_call_span,
+ place_name: &place_name,
+ is_partial,
+ is_loop_message,
+ });
+ }
// Erase and shadow everything that could be passed to the new infcx.
- let ty = tcx.erase_regions(moved_place.ty(self.body, tcx).ty);
- let method_substs = tcx.erase_regions(method_substs);
+ let ty = moved_place.ty(self.body, tcx).ty;
if let ty::Adt(def, substs) = ty.kind()
&& Some(def.did()) == tcx.lang_items().pin_type()
&& let ty::Ref(_, _, hir::Mutability::Mut) = substs.type_at(0).kind()
- && let self_ty = infcx.instantiate_binder_with_fresh_vars(
+ && let self_ty = self.infcx.instantiate_binder_with_fresh_vars(
fn_call_span,
LateBoundRegionConversionTime::FnCall,
tcx.fn_sig(method_did).subst(tcx, method_substs).input(0),
)
- && infcx.can_eq(self.param_env, ty, self_ty)
+ && self.infcx.can_eq(self.param_env, ty, self_ty)
{
- err.span_suggestion_verbose(
- fn_call_span.shrink_to_lo(),
- "consider reborrowing the `Pin` instead of moving it",
- "as_mut().".to_string(),
- Applicability::MaybeIncorrect,
- );
+ err.eager_subdiagnostic(
+ &self.infcx.tcx.sess.parse_sess.span_diagnostic,
+ CaptureReasonSuggest::FreshReborrow {
+ span: fn_call_span.shrink_to_lo(),
+ });
}
if let Some(clone_trait) = tcx.lang_items().clone_trait()
- && let trait_ref = tcx.mk_trait_ref(clone_trait, [ty])
+ && let trait_ref = ty::TraitRef::new(tcx, clone_trait, [ty])
&& let o = Obligation::new(
tcx,
ObligationCause::dummy(),
self.param_env,
ty::Binder::dummy(trait_ref),
)
- && infcx.predicate_must_hold_modulo_regions(&o)
+ && self.infcx.predicate_must_hold_modulo_regions(&o)
{
err.span_suggestion_verbose(
fn_call_span.shrink_to_lo(),
@@ -1177,10 +1142,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// error messages.
if span != DUMMY_SP && self.fn_self_span_reported.insert(self_arg.span) {
let func = tcx.def_path_str(method_did);
- err.span_note(
- self_arg.span,
- &format!("`{func}` takes ownership of the receiver `self`, which moves {place_name}")
- );
+ err.subdiagnostic(CaptureReasonNote::FuncTakeSelf {
+ func,
+ place_name,
+ span: self_arg.span,
+ });
}
let parent_did = tcx.parent(method_did);
let parent_self_ty =
@@ -1190,34 +1156,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
ty::Adt(def, ..) => Some(def.did()),
_ => None,
});
- let is_option_or_result = parent_self_ty.map_or(false, |def_id| {
+ let is_option_or_result = parent_self_ty.is_some_and(|def_id| {
matches!(tcx.get_diagnostic_name(def_id), Some(sym::Option | sym::Result))
});
if is_option_or_result && maybe_reinitialized_locations_is_empty {
- err.span_label(
- var_span,
- "help: consider calling `.as_ref()` or `.as_mut()` to borrow the type's contents",
- );
+ err.subdiagnostic(CaptureReasonLabel::BorrowContent { var_span });
}
}
// Other desugarings takes &self, which cannot cause a move
_ => {}
}
} else {
- if move_span != span || !loop_message.is_empty() {
- err.span_label(
+ if move_span != span || is_loop_message {
+ err.subdiagnostic(CaptureReasonLabel::MovedHere {
move_span,
- format!("value {partially_str}moved{move_msg} here{loop_message}"),
- );
+ is_partial,
+ is_move_msg,
+ is_loop_message,
+ });
}
// If the move error occurs due to a loop, don't show
// another message for the same span
- if loop_message.is_empty() {
- move_spans.var_span_label(
- err,
- format!("variable {partially_str}moved due to use{}", move_spans.describe()),
- "moved",
- );
+ if !is_loop_message {
+ move_spans.var_subdiag(None, err, None, |kind, var_span| match kind {
+ Some(_) => CaptureVarCause::PartialMoveUseInGenerator { var_span, is_partial },
+ None => CaptureVarCause::PartialMoveUseInClosure { var_span, is_partial },
+ })
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
index 3662bec0c..8b77477a3 100644
--- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs
@@ -6,6 +6,7 @@ use rustc_mir_dataflow::move_paths::{
};
use rustc_span::{BytePos, Span};
+use crate::diagnostics::CapturedMessageOpt;
use crate::diagnostics::{DescribePlaceOpt, UseSpans};
use crate::prefixes::PrefixSet;
use crate::MirBorrowckCtxt;
@@ -397,10 +398,15 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
};
+ let msg_opt = CapturedMessageOpt {
+ is_partial_move: false,
+ is_loop_message: false,
+ is_move_msg: false,
+ is_loop_move: false,
+ maybe_reinitialized_locations_is_empty: true,
+ };
if let Some(use_spans) = use_spans {
- self.explain_captures(
- &mut err, span, span, use_spans, move_place, "", "", "", false, true,
- );
+ self.explain_captures(&mut err, span, span, use_spans, move_place, msg_opt);
}
err
}
@@ -416,13 +422,12 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
None => "value".to_string(),
};
- self.note_type_does_not_implement_copy(
- err,
- &place_desc,
- place_ty,
- Some(span),
- "",
- );
+ err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+ is_partial_move: false,
+ ty: place_ty,
+ place: &place_desc,
+ span,
+ });
} else {
binds_to.sort();
binds_to.dedup();
@@ -444,9 +449,19 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
Some(desc) => format!("`{desc}`"),
None => "value".to_string(),
};
- self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span), "");
+ err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+ is_partial_move: false,
+ ty: place_ty,
+ place: &place_desc,
+ span,
+ });
- use_spans.args_span_label(err, format!("{place_desc} is moved here"));
+ use_spans.args_subdiag(err, |args_span| {
+ crate::session_diagnostics::CaptureArgLabel::MoveOutPlace {
+ place: place_desc,
+ args_span,
+ }
+ });
}
}
}
@@ -518,7 +533,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
suggestions.sort_unstable_by_key(|&(span, _, _)| span);
suggestions.dedup_by_key(|&mut (span, _, _)| span);
for (span, msg, suggestion) in suggestions {
- err.span_suggestion_verbose(span, &msg, suggestion, Applicability::MachineApplicable);
+ err.span_suggestion_verbose(span, msg, suggestion, Applicability::MachineApplicable);
}
}
@@ -534,13 +549,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
if binds_to.len() == 1 {
- self.note_type_does_not_implement_copy(
- err,
- &format!("`{}`", self.local_names[*local].unwrap()),
- bind_to.ty,
- Some(binding_span),
- "",
- );
+ let place_desc = &format!("`{}`", self.local_names[*local].unwrap());
+ err.subdiagnostic(crate::session_diagnostics::TypeNoCopy::Label {
+ is_partial_move: false,
+ ty: bind_to.ty,
+ place: &place_desc,
+ span: binding_span,
+ });
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
index 9d9040096..d0e17bf5a 100644
--- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs
@@ -1,4 +1,4 @@
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_hir::intravisit::Visitor;
use rustc_hir::Node;
@@ -15,8 +15,8 @@ use rustc_span::{sym, BytePos, Span};
use rustc_target::abi::FieldIdx;
use crate::diagnostics::BorrowedContentSource;
+use crate::util::FindAssignments;
use crate::MirBorrowckCtxt;
-use rustc_const_eval::util::collect_writes::FindAssignments;
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum AccessKind {
@@ -231,14 +231,18 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
if suggest {
- borrow_spans.var_span_label(
- &mut err,
- format!(
- "mutable borrow occurs due to use of {} in closure",
- self.describe_any_place(access_place.as_ref()),
- ),
- "mutable",
- );
+ borrow_spans.var_subdiag(
+ None,
+ &mut err,
+ Some(mir::BorrowKind::Mut { allow_two_phase_borrow: false }),
+ |_kind, var_span| {
+ let place = self.describe_any_place(access_place.as_ref());
+ crate::session_diagnostics::CaptureVarCause::MutableBorrowUsePlaceClosure {
+ place,
+ var_span,
+ }
+ },
+ );
}
borrow_span
}
@@ -285,8 +289,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.body
.local_decls
.get(local)
- .map(|l| mut_borrow_of_mutable_ref(l, self.local_names[local]))
- .unwrap_or(false) =>
+ .is_some_and(|l| mut_borrow_of_mutable_ref(l, self.local_names[local])) =>
{
let decl = &self.body.local_decls[local];
err.span_label(span, format!("cannot {act}"));
@@ -439,7 +442,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
.sess
.source_map()
.span_to_snippet(span)
- .map_or(false, |snippet| snippet.starts_with("&mut ")) =>
+ .is_ok_and(|snippet| snippet.starts_with("&mut ")) =>
{
err.span_label(span, format!("cannot {act}"));
err.span_suggestion(
@@ -474,179 +477,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match self.local_names[local] {
Some(name) if !local_decl.from_compiler_desugaring() => {
- let label = match *local_decl.local_info() {
- LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
- let (span, suggestion) =
- suggest_ampmut_self(self.infcx.tcx, local_decl);
- Some((true, span, suggestion))
- }
-
- LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
- binding_mode: ty::BindingMode::BindByValue(_),
- opt_ty_info,
- ..
- })) => {
- // check if the RHS is from desugaring
- let opt_assignment_rhs_span =
- self.body.find_assignments(local).first().map(|&location| {
- if let Some(mir::Statement {
- source_info: _,
- kind:
- mir::StatementKind::Assign(box (
- _,
- mir::Rvalue::Use(mir::Operand::Copy(place)),
- )),
- }) = self.body[location.block]
- .statements
- .get(location.statement_index)
- {
- self.body.local_decls[place.local].source_info.span
- } else {
- self.body.source_info(location).span
- }
- });
- match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
- // on for loops, RHS points to the iterator part
- Some(DesugaringKind::ForLoop) => {
- self.suggest_similar_mut_method_for_for_loop(&mut err);
- err.span_label(opt_assignment_rhs_span.unwrap(), format!(
- "this iterator yields `{pointer_sigil}` {pointer_desc}s",
- ));
- None
- }
- // don't create labels for compiler-generated spans
- Some(_) => None,
- None => {
- let label = if name != kw::SelfLower {
- suggest_ampmut(
- self.infcx.tcx,
- local_decl,
- opt_assignment_rhs_span,
- opt_ty_info,
- )
- } else {
- match local_decl.local_info() {
- LocalInfo::User(mir::BindingForm::Var(
- mir::VarBindingForm {
- opt_ty_info: None, ..
- },
- )) => {
- let (span, sugg) = suggest_ampmut_self(
- self.infcx.tcx,
- local_decl,
- );
- (true, span, sugg)
- }
- // explicit self (eg `self: &'a Self`)
- _ => suggest_ampmut(
- self.infcx.tcx,
- local_decl,
- opt_assignment_rhs_span,
- opt_ty_info,
- ),
- }
- };
- Some(label)
- }
- }
- }
-
- LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
- binding_mode: ty::BindingMode::BindByReference(_),
- ..
- })) => {
- let pattern_span = local_decl.source_info.span;
- suggest_ref_mut(self.infcx.tcx, pattern_span)
- .map(|replacement| (true, pattern_span, replacement))
- }
-
- _ => unreachable!(),
- };
-
- match label {
- Some((true, err_help_span, suggested_code)) => {
- let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
- if !is_trait_sig {
- err.span_suggestion_verbose(
- err_help_span,
- &format!(
- "consider changing this to be a mutable {pointer_desc}"
- ),
- suggested_code,
- Applicability::MachineApplicable,
- );
- } else if let Some(x) = local_trait {
- err.span_suggestion_verbose(
- x,
- &format!(
- "consider changing that to be a mutable {pointer_desc}"
- ),
- suggested_code,
- Applicability::MachineApplicable,
- );
- }
- }
- Some((false, err_label_span, message)) => {
- struct BindingFinder {
- span: Span,
- hir_id: Option<hir::HirId>,
- }
-
- impl<'tcx> Visitor<'tcx> for BindingFinder {
- fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
- if let hir::StmtKind::Local(local) = s.kind {
- if local.pat.span == self.span {
- self.hir_id = Some(local.hir_id);
- }
- }
- hir::intravisit::walk_stmt(self, s);
- }
- }
- let hir_map = self.infcx.tcx.hir();
- let def_id = self.body.source.def_id();
- let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
- let node = hir_map.find(hir_id);
- let hir_id = if let Some(hir::Node::Item(item)) = node
- && let hir::ItemKind::Fn(.., body_id) = item.kind
- {
- let body = hir_map.body(body_id);
- let mut v = BindingFinder {
- span: err_label_span,
- hir_id: None,
- };
- v.visit_body(body);
- v.hir_id
- } else {
- None
- };
- if let Some(hir_id) = hir_id
- && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
- {
- let (changing, span, sugg) = match local.ty {
- Some(ty) => ("changing", ty.span, message),
- None => (
- "specifying",
- local.pat.span.shrink_to_hi(),
- format!(": {message}"),
- ),
- };
- err.span_suggestion_verbose(
- span,
- &format!("consider {changing} this binding's type"),
- sugg,
- Applicability::HasPlaceholders,
- );
- } else {
- err.span_label(
- err_label_span,
- &format!(
- "consider changing this binding's type to be: `{message}`"
- ),
- );
- }
- }
- None => {}
- }
err.span_label(
span,
format!(
@@ -654,6 +484,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
so the data it refers to cannot be {acted_on}",
),
);
+
+ self.suggest_make_local_mut(&mut err, local, name);
}
_ => {
err.span_label(
@@ -675,13 +507,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
match opt_source {
Some(BorrowedContentSource::OverloadedDeref(ty)) => {
- err.help(&format!(
+ err.help(format!(
"trait `DerefMut` is required to modify through a dereference, \
but it is not implemented for `{ty}`",
));
}
Some(BorrowedContentSource::OverloadedIndex(ty)) => {
- err.help(&format!(
+ err.help(format!(
"trait `IndexMut` is required to modify indexed content, \
but it is not implemented for `{ty}`",
));
@@ -732,7 +564,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
// val[index] = rv;
// ---------- place
self.err.multipart_suggestions(
- &format!(
+ format!(
"to modify a `{}`, use `.get_mut()`, `.insert()` or the entry API",
self.ty,
),
@@ -784,7 +616,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
{
// val[index].path(args..);
self.err.multipart_suggestion(
- &format!("to modify a `{}` use `.get_mut()`", self.ty),
+ format!("to modify a `{}` use `.get_mut()`", self.ty),
vec![
(
val.span.shrink_to_hi().with_hi(index.span.lo()),
@@ -809,16 +641,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
let Some(hir::Node::Item(item)) = node else { return; };
let hir::ItemKind::Fn(.., body_id) = item.kind else { return; };
let body = self.infcx.tcx.hir().body(body_id);
- let mut assign_span = span;
- // Drop desugaring is done at MIR build so it's not in the HIR
- if let Some(DesugaringKind::Replace) = span.desugaring_kind() {
- assign_span.remove_mark();
- }
- let mut v = V { assign_span, err, ty, suggested: false };
+ let mut v = V { assign_span: span, err, ty, suggested: false };
v.visit_body(body);
if !v.suggested {
- err.help(&format!(
+ err.help(format!(
"to modify a `{ty}`, use `.get_mut()`, `.insert()` or the entry API",
));
}
@@ -1127,6 +954,184 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
}
}
+
+ fn suggest_make_local_mut(
+ &self,
+ err: &mut DiagnosticBuilder<'_, ErrorGuaranteed>,
+ local: Local,
+ name: Symbol,
+ ) {
+ let local_decl = &self.body.local_decls[local];
+
+ let (pointer_sigil, pointer_desc) =
+ if local_decl.ty.is_ref() { ("&", "reference") } else { ("*const", "pointer") };
+
+ let (is_trait_sig, local_trait) = self.is_error_in_trait(local);
+ if is_trait_sig && local_trait.is_none() {
+ return;
+ }
+
+ let decl_span = match local_trait {
+ Some(span) => span,
+ None => local_decl.source_info.span,
+ };
+
+ let label = match *local_decl.local_info() {
+ LocalInfo::User(mir::BindingForm::ImplicitSelf(_)) => {
+ let suggestion = suggest_ampmut_self(self.infcx.tcx, decl_span);
+ Some((true, decl_span, suggestion))
+ }
+
+ LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByValue(_),
+ opt_ty_info,
+ ..
+ })) => {
+ // check if the RHS is from desugaring
+ let opt_assignment_rhs_span =
+ self.body.find_assignments(local).first().map(|&location| {
+ if let Some(mir::Statement {
+ source_info: _,
+ kind:
+ mir::StatementKind::Assign(box (
+ _,
+ mir::Rvalue::Use(mir::Operand::Copy(place)),
+ )),
+ }) = self.body[location.block].statements.get(location.statement_index)
+ {
+ self.body.local_decls[place.local].source_info.span
+ } else {
+ self.body.source_info(location).span
+ }
+ });
+ match opt_assignment_rhs_span.and_then(|s| s.desugaring_kind()) {
+ // on for loops, RHS points to the iterator part
+ Some(DesugaringKind::ForLoop) => {
+ self.suggest_similar_mut_method_for_for_loop(err);
+ err.span_label(
+ opt_assignment_rhs_span.unwrap(),
+ format!("this iterator yields `{pointer_sigil}` {pointer_desc}s",),
+ );
+ None
+ }
+ // don't create labels for compiler-generated spans
+ Some(_) => None,
+ None => {
+ let label = if name != kw::SelfLower {
+ suggest_ampmut(
+ self.infcx.tcx,
+ local_decl.ty,
+ decl_span,
+ opt_assignment_rhs_span,
+ opt_ty_info,
+ )
+ } else {
+ match local_decl.local_info() {
+ LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+ opt_ty_info: None,
+ ..
+ })) => {
+ let sugg = suggest_ampmut_self(self.infcx.tcx, decl_span);
+ (true, decl_span, sugg)
+ }
+ // explicit self (eg `self: &'a Self`)
+ _ => suggest_ampmut(
+ self.infcx.tcx,
+ local_decl.ty,
+ decl_span,
+ opt_assignment_rhs_span,
+ opt_ty_info,
+ ),
+ }
+ };
+ Some(label)
+ }
+ }
+ }
+
+ LocalInfo::User(mir::BindingForm::Var(mir::VarBindingForm {
+ binding_mode: ty::BindingMode::BindByReference(_),
+ ..
+ })) => {
+ let pattern_span: Span = local_decl.source_info.span;
+ suggest_ref_mut(self.infcx.tcx, pattern_span)
+ .map(|span| (true, span, "mut ".to_owned()))
+ }
+
+ _ => unreachable!(),
+ };
+
+ match label {
+ Some((true, err_help_span, suggested_code)) => {
+ err.span_suggestion_verbose(
+ err_help_span,
+ format!("consider changing this to be a mutable {pointer_desc}"),
+ suggested_code,
+ Applicability::MachineApplicable,
+ );
+ }
+ Some((false, err_label_span, message)) => {
+ struct BindingFinder {
+ span: Span,
+ hir_id: Option<hir::HirId>,
+ }
+
+ impl<'tcx> Visitor<'tcx> for BindingFinder {
+ fn visit_stmt(&mut self, s: &'tcx hir::Stmt<'tcx>) {
+ if let hir::StmtKind::Local(local) = s.kind {
+ if local.pat.span == self.span {
+ self.hir_id = Some(local.hir_id);
+ }
+ }
+ hir::intravisit::walk_stmt(self, s);
+ }
+ }
+ let hir_map = self.infcx.tcx.hir();
+ let def_id = self.body.source.def_id();
+ let hir_id = hir_map.local_def_id_to_hir_id(def_id.expect_local());
+ let node = hir_map.find(hir_id);
+ let hir_id = if let Some(hir::Node::Item(item)) = node
+ && let hir::ItemKind::Fn(.., body_id) = item.kind
+ {
+ let body = hir_map.body(body_id);
+ let mut v = BindingFinder {
+ span: err_label_span,
+ hir_id: None,
+ };
+ v.visit_body(body);
+ v.hir_id
+ } else {
+ None
+ };
+ if let Some(hir_id) = hir_id
+ && let Some(hir::Node::Local(local)) = hir_map.find(hir_id)
+ {
+ let (changing, span, sugg) = match local.ty {
+ Some(ty) => ("changing", ty.span, message),
+ None => (
+ "specifying",
+ local.pat.span.shrink_to_hi(),
+ format!(": {message}"),
+ ),
+ };
+ err.span_suggestion_verbose(
+ span,
+ format!("consider {changing} this binding's type"),
+ sugg,
+ Applicability::HasPlaceholders,
+ );
+ } else {
+ err.span_label(
+ err_label_span,
+ format!(
+ "consider changing this binding's type to be: `{message}`"
+ ),
+ );
+ }
+ }
+ None => {}
+ }
+ }
}
pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<Symbol>) -> bool {
@@ -1143,7 +1148,7 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
// suggest removing the `&mut`.
//
// Deliberately fall into this case for all implicit self types,
- // so that we don't fall in to the next case with them.
+ // so that we don't fall into the next case with them.
kind == hir::ImplicitSelfKind::MutRef
}
_ if Some(kw::SelfLower) == local_name => {
@@ -1156,25 +1161,18 @@ pub fn mut_borrow_of_mutable_ref(local_decl: &LocalDecl<'_>, local_name: Option<
}
}
-fn suggest_ampmut_self<'tcx>(
- tcx: TyCtxt<'tcx>,
- local_decl: &mir::LocalDecl<'tcx>,
-) -> (Span, String) {
- let sp = local_decl.source_info.span;
- (
- sp,
- match tcx.sess.source_map().span_to_snippet(sp) {
- Ok(snippet) => {
- let lt_pos = snippet.find('\'');
- if let Some(lt_pos) = lt_pos {
- format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
- } else {
- "&mut self".to_string()
- }
+fn suggest_ampmut_self<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String {
+ match tcx.sess.source_map().span_to_snippet(span) {
+ Ok(snippet) => {
+ let lt_pos = snippet.find('\'');
+ if let Some(lt_pos) = lt_pos {
+ format!("&{}mut self", &snippet[lt_pos..snippet.len() - 4])
+ } else {
+ "&mut self".to_string()
}
- _ => "&mut self".to_string(),
- },
- )
+ }
+ _ => "&mut self".to_string(),
+ }
}
// When we want to suggest a user change a local variable to be a `&mut`, there
@@ -1194,72 +1192,89 @@ fn suggest_ampmut_self<'tcx>(
// by trying (3.), then (2.) and finally falling back on (1.).
fn suggest_ampmut<'tcx>(
tcx: TyCtxt<'tcx>,
- local_decl: &mir::LocalDecl<'tcx>,
+ decl_ty: Ty<'tcx>,
+ decl_span: Span,
opt_assignment_rhs_span: Option<Span>,
opt_ty_info: Option<Span>,
) -> (bool, Span, String) {
+ // if there is a RHS and it starts with a `&` from it, then check if it is
+ // mutable, and if not, put suggest putting `mut ` to make it mutable.
+ // we don't have to worry about lifetime annotations here because they are
+ // not valid when taking a reference. For example, the following is not valid Rust:
+ //
+ // let x: &i32 = &'a 5;
+ // ^^ lifetime annotation not allowed
+ //
if let Some(assignment_rhs_span) = opt_assignment_rhs_span
&& let Ok(src) = tcx.sess.source_map().span_to_snippet(assignment_rhs_span)
+ && let Some(stripped) = src.strip_prefix('&')
{
- let is_mutbl = |ty: &str| -> bool {
- if let Some(rest) = ty.strip_prefix("mut") {
- match rest.chars().next() {
- // e.g. `&mut x`
- Some(c) if c.is_whitespace() => true,
- // e.g. `&mut(x)`
- Some('(') => true,
- // e.g. `&mut{x}`
- Some('{') => true,
- // e.g. `&mutablevar`
- _ => false,
- }
- } else {
- false
+ let is_mut = if let Some(rest) = stripped.trim_start().strip_prefix("mut") {
+ match rest.chars().next() {
+ // e.g. `&mut x`
+ Some(c) if c.is_whitespace() => true,
+ // e.g. `&mut(x)`
+ Some('(') => true,
+ // e.g. `&mut{x}`
+ Some('{') => true,
+ // e.g. `&mutablevar`
+ _ => false,
}
+ } else {
+ false
};
- if let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace)) {
- let lt_name = &src[1..ws_pos];
- let ty = src[ws_pos..].trim_start();
- if !is_mutbl(ty) {
- return (true, assignment_rhs_span, format!("&{lt_name} mut {ty}"));
- }
- } else if let Some(stripped) = src.strip_prefix('&') {
- let stripped = stripped.trim_start();
- if !is_mutbl(stripped) {
- return (true, assignment_rhs_span, format!("&mut {stripped}"));
- }
+ // if the reference is already mutable then there is nothing we can do
+ // here.
+ if !is_mut {
+ let span = assignment_rhs_span;
+ // shrink the span to just after the `&` in `&variable`
+ let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
+
+ // FIXME(Ezrashaw): returning is bad because we still might want to
+ // update the annotated type, see #106857.
+ return (true, span, "mut ".to_owned());
}
}
- let (suggestability, highlight_span) = match opt_ty_info {
+ let (binding_exists, span) = match opt_ty_info {
// if this is a variable binding with an explicit type,
- // try to highlight that for the suggestion.
+ // then we will suggest changing it to be mutable.
+ // this is `Applicability::MachineApplicable`.
Some(ty_span) => (true, ty_span),
- // otherwise, just highlight the span associated with
- // the (MIR) LocalDecl.
- None => (false, local_decl.source_info.span),
+ // otherwise, we'll suggest *adding* an annotated type, we'll suggest
+ // the RHS's type for that.
+ // this is `Applicability::HasPlaceholders`.
+ None => (false, decl_span),
};
- if let Ok(src) = tcx.sess.source_map().span_to_snippet(highlight_span)
- && let (true, Some(ws_pos)) = (src.starts_with("&'"), src.find(char::is_whitespace))
+ // if the binding already exists and is a reference with a explicit
+ // lifetime, then we can suggest adding ` mut`. this is special-cased from
+ // the path without a explicit lifetime.
+ if let Ok(src) = tcx.sess.source_map().span_to_snippet(span)
+ && src.starts_with("&'")
+ // note that `& 'a T` is invalid so this is correct.
+ && let Some(ws_pos) = src.find(char::is_whitespace)
{
- let lt_name = &src[1..ws_pos];
- let ty = &src[ws_pos..];
- return (true, highlight_span, format!("&{lt_name} mut{ty}"));
- }
+ let span = span.with_lo(span.lo() + BytePos(ws_pos as u32)).shrink_to_lo();
+ (true, span, " mut".to_owned())
+ // if there is already a binding, we modify it to be `mut`
+ } else if binding_exists {
+ // shrink the span to just after the `&` in `&variable`
+ let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo();
+ (true, span, "mut ".to_owned())
+ } else {
+ // otherwise, suggest that the user annotates the binding; we provide the
+ // type of the local.
+ let ty_mut = decl_ty.builtin_deref(true).unwrap();
+ assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
- let ty_mut = local_decl.ty.builtin_deref(true).unwrap();
- assert_eq!(ty_mut.mutbl, hir::Mutability::Not);
- (
- suggestability,
- highlight_span,
- if local_decl.ty.is_ref() {
- format!("&mut {}", ty_mut.ty)
- } else {
- format!("*mut {}", ty_mut.ty)
- },
- )
+ (
+ false,
+ span,
+ format!("{}mut {}", if decl_ty.is_ref() {"&"} else {"*"}, ty_mut.ty)
+ )
+ }
}
fn is_closure_or_generator(ty: Ty<'_>) -> bool {
@@ -1296,11 +1311,13 @@ fn get_mut_span_in_struct_field<'tcx>(
}
/// If possible, suggest replacing `ref` with `ref mut`.
-fn suggest_ref_mut(tcx: TyCtxt<'_>, binding_span: Span) -> Option<String> {
- let hi_src = tcx.sess.source_map().span_to_snippet(binding_span).ok()?;
- if hi_src.starts_with("ref") && hi_src["ref".len()..].starts_with(rustc_lexer::is_whitespace) {
- let replacement = format!("ref mut{}", &hi_src["ref".len()..]);
- Some(replacement)
+fn suggest_ref_mut(tcx: TyCtxt<'_>, span: Span) -> Option<Span> {
+ let pattern_str = tcx.sess.source_map().span_to_snippet(span).ok()?;
+ if pattern_str.starts_with("ref")
+ && pattern_str["ref".len()..].starts_with(rustc_lexer::is_whitespace)
+ {
+ let span = span.with_lo(span.lo() + BytePos(4)).shrink_to_lo();
+ Some(span)
} else {
None
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
index d5ece5743..b6eb9ae98 100644
--- a/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/outlives_suggestion.rs
@@ -125,8 +125,7 @@ impl OutlivesSuggestionBuilder {
|(r, _)| {
self.constraints_to_add
.get(r)
- .map(|r_outlived| r_outlived.as_slice().contains(fr))
- .unwrap_or(false)
+ .is_some_and(|r_outlived| r_outlived.as_slice().contains(fr))
},
);
@@ -171,7 +170,7 @@ impl OutlivesSuggestionBuilder {
if let (Some(fr_name), Some(outlived_fr_name)) = (fr_name, outlived_fr_name)
&& !matches!(outlived_fr_name.source, RegionNameSource::Static)
{
- diag.help(&format!(
+ diag.help(format!(
"consider adding the following bound: `{fr_name}: {outlived_fr_name}`",
));
}
@@ -207,7 +206,7 @@ impl OutlivesSuggestionBuilder {
// If there is exactly one suggestable constraints, then just suggest it. Otherwise, emit a
// list of diagnostics.
let mut diag = if suggested.len() == 1 {
- mbcx.infcx.tcx.sess.diagnostic().struct_help(&match suggested.last().unwrap() {
+ mbcx.infcx.tcx.sess.diagnostic().struct_help(match suggested.last().unwrap() {
SuggestedConstraint::Outlives(a, bs) => {
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
format!("add bound `{a}: {}`", bs.join(" + "))
@@ -232,15 +231,15 @@ impl OutlivesSuggestionBuilder {
match constraint {
SuggestedConstraint::Outlives(a, bs) => {
let bs: SmallVec<[String; 2]> = bs.iter().map(|r| r.to_string()).collect();
- diag.help(&format!("add bound `{a}: {}`", bs.join(" + ")));
+ diag.help(format!("add bound `{a}: {}`", bs.join(" + ")));
}
SuggestedConstraint::Equal(a, b) => {
- diag.help(&format!(
+ diag.help(format!(
"`{a}` and `{b}` must be the same: replace one with the other",
));
}
SuggestedConstraint::Static(a) => {
- diag.help(&format!("replace `{a}` with `'static`"));
+ diag.help(format!("replace `{a}` with `'static`"));
}
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
index 9fcebeb0a..8ec872e20 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs
@@ -533,8 +533,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
}
_ => panic!("Unexpected type {ty:?}"),
};
- diag.note(&format!("requirement occurs because of {desc}",));
- diag.note(&note);
+ diag.note(format!("requirement occurs because of {desc}",));
+ diag.note(note);
diag.help("see <https://doc.rust-lang.org/nomicon/subtyping.html> for more information about variance");
}
}
@@ -845,7 +845,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
return;
}
- let Some((alias_tys, alias_span)) = self
+ let Some((alias_tys, alias_span, lt_addition_span)) = self
.infcx
.tcx
.return_type_impl_or_dyn_traits_with_type_alias(suitable_region.def_id) else { return; };
@@ -858,12 +858,22 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> {
()
}
if let TyKind::TraitObject(_, lt, _) = alias_ty.kind {
- spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+ if lt.ident.name == kw::Empty {
+ spans_suggs.push((lt.ident.span.shrink_to_hi(), " + 'a".to_string()));
+ } else {
+ spans_suggs.push((lt.ident.span, "'a".to_string()));
+ }
}
}
- spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+
+ if let Some(lt_addition_span) = lt_addition_span {
+ spans_suggs.push((lt_addition_span, "'a, ".to_string()));
+ } else {
+ spans_suggs.push((alias_span.shrink_to_hi(), "<'a>".to_string()));
+ }
+
diag.multipart_suggestion_verbose(
- &format!(
+ format!(
"to declare that the trait object {captures}, you can add a lifetime parameter `'a` in the type alias"
),
spans_suggs,
diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
index f69c4829a..f38e1605f 100644
--- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs
@@ -622,7 +622,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> {
// programs, so we need to use delay_span_bug here. See #82126.
self.infcx.tcx.sess.delay_span_bug(
hir_arg.span(),
- &format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
+ format!("unmatched subst and hir arg: found {kind:?} vs {hir_arg:?}"),
);
}
}
diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
index 376415e3d..98418e237 100644
--- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs
+++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs
@@ -3,7 +3,7 @@
use crate::region_infer::RegionInferenceContext;
use crate::Upvar;
-use rustc_index::vec::{Idx, IndexSlice};
+use rustc_index::IndexSlice;
use rustc_middle::mir::{Body, Local};
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_span::source_map::Span;
@@ -117,7 +117,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
argument_index: usize,
) -> (Option<Symbol>, Span) {
let implicit_inputs = self.universal_regions().defining_ty.implicit_inputs();
- let argument_local = Local::new(implicit_inputs + argument_index + 1);
+ let argument_local = Local::from_usize(implicit_inputs + argument_index + 1);
debug!("get_argument_name_and_span_for_region: argument_local={argument_local:?}");
let argument_name = local_names[argument_local];
diff --git a/compiler/rustc_borrowck/src/facts.rs b/compiler/rustc_borrowck/src/facts.rs
index 02ffb51fb..87fad9a35 100644
--- a/compiler/rustc_borrowck/src/facts.rs
+++ b/compiler/rustc_borrowck/src/facts.rs
@@ -4,7 +4,6 @@ use crate::location::{LocationIndex, LocationTable};
use crate::BorrowIndex;
use polonius_engine::AllFacts as PoloniusFacts;
use polonius_engine::Atom;
-use rustc_index::vec::Idx;
use rustc_middle::mir::Local;
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::move_paths::MovePathIndex;
@@ -93,13 +92,13 @@ impl AllFactsExt for AllFacts {
impl Atom for BorrowIndex {
fn index(self) -> usize {
- Idx::index(self)
+ self.as_usize()
}
}
impl Atom for LocationIndex {
fn index(self) -> usize {
- Idx::index(self)
+ self.as_usize()
}
}
diff --git a/compiler/rustc_borrowck/src/invalidation.rs b/compiler/rustc_borrowck/src/invalidation.rs
index 498d254da..b2ff25ecb 100644
--- a/compiler/rustc_borrowck/src/invalidation.rs
+++ b/compiler/rustc_borrowck/src/invalidation.rs
@@ -46,7 +46,7 @@ struct InvalidationGenerator<'cx, 'tcx> {
all_facts: &'cx mut AllFacts,
location_table: &'cx LocationTable,
body: &'cx Body<'tcx>,
- dominators: Dominators<BasicBlock>,
+ dominators: &'cx Dominators<BasicBlock>,
borrow_set: &'cx BorrowSet<'tcx>,
}
@@ -79,7 +79,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
}
// Only relevant for mir typeck
StatementKind::AscribeUserType(..)
- // Only relevant for unsafeck
+ // Only relevant for liveness and unsafeck
| StatementKind::PlaceMention(..)
// Doesn't have any language semantics
| StatementKind::Coverage(..)
@@ -112,11 +112,13 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(location, discr);
}
- TerminatorKind::Drop { place: drop_place, target: _, unwind: _ } => {
+ TerminatorKind::Drop { place: drop_place, target: _, unwind: _, replace } => {
+ let write_kind =
+ if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
self.access_place(
location,
*drop_place,
- (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
+ (AccessDepth::Drop, Write(write_kind)),
LocalMutationIsAllowed::Yes,
);
}
@@ -138,7 +140,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for InvalidationGenerator<'cx, 'tcx> {
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(location, cond);
use rustc_middle::mir::AssertKind;
- if let AssertKind::BoundsCheck { len, index } = msg {
+ if let AssertKind::BoundsCheck { len, index } = &**msg {
self.consume_operand(location, len);
self.consume_operand(location, index);
}
diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs
index a4b285a34..a53ea100c 100644
--- a/compiler/rustc_borrowck/src/lib.rs
+++ b/compiler/rustc_borrowck/src/lib.rs
@@ -20,14 +20,14 @@ extern crate tracing;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::dominators::Dominators;
use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::ChunkedBitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::{
- DefiningAnchor, InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
+ InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin, TyCtxtInferExt,
};
-use rustc_macros::fluent_messages;
use rustc_middle::mir::{
traversal, Body, ClearCrossCrate, Local, Location, Mutability, NonDivergingIntrinsic, Operand,
Place, PlaceElem, PlaceRef, VarDebugInfoContents,
@@ -35,7 +35,8 @@ use rustc_middle::mir::{
use rustc_middle::mir::{AggregateKind, BasicBlock, BorrowCheckResult, BorrowKind};
use rustc_middle::mir::{InlineAsmOperand, Terminator, TerminatorKind};
use rustc_middle::mir::{ProjectionElem, Promoted, Rvalue, Statement, StatementKind};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt};
use rustc_session::lint::builtin::UNUSED_MUT;
use rustc_span::{Span, Symbol};
@@ -43,7 +44,6 @@ use rustc_target::abi::FieldIdx;
use either::Either;
use smallvec::SmallVec;
-use std::cell::OnceCell;
use std::cell::RefCell;
use std::collections::BTreeMap;
use std::ops::Deref;
@@ -62,7 +62,7 @@ use crate::session_diagnostics::VarNeedNotMut;
use self::diagnostics::{AccessKind, RegionName};
use self::location::LocationTable;
use self::prefixes::PrefixSet;
-use facts::AllFacts;
+use consumers::{BodyWithBorrowckFacts, ConsumerOptions};
use self::path_utils::*;
@@ -88,6 +88,7 @@ mod session_diagnostics;
mod type_check;
mod universal_regions;
mod used_muts;
+mod util;
/// A public API provided for the Rust compiler consumers.
pub mod consumers;
@@ -118,24 +119,12 @@ impl<'tcx> TyCtxtConsts<'tcx> {
}
pub fn provide(providers: &mut Providers) {
- *providers = Providers {
- mir_borrowck: |tcx, did| {
- if let Some(def) = ty::WithOptConstParam::try_lookup(did, tcx) {
- tcx.mir_borrowck_const_arg(def)
- } else {
- mir_borrowck(tcx, ty::WithOptConstParam::unknown(did))
- }
- },
- mir_borrowck_const_arg: |tcx, (did, param_did)| {
- mir_borrowck(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
- },
- ..*providers
- };
+ *providers = Providers { mir_borrowck, ..*providers };
}
-fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &BorrowCheckResult<'_> {
+fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> {
let (input_body, promoted) = tcx.mir_promoted(def);
- debug!("run query mir_borrowck: {}", tcx.def_path_str(def.did.to_def_id()));
+ debug!("run query mir_borrowck: {}", tcx.def_path_str(def));
if input_body.borrow().should_skip() {
debug!("Skipping borrowck because of injected body");
@@ -149,13 +138,13 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor
return tcx.arena.alloc(result);
}
- let hir_owner = tcx.hir().local_def_id_to_hir_id(def.did).owner;
+ let hir_owner = tcx.hir().local_def_id_to_hir_id(def).owner;
let infcx =
tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build();
let input_body: &Body<'_> = &input_body.borrow();
let promoted: &IndexSlice<_, _> = &promoted.borrow();
- let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, false).0;
+ let opt_closure_req = do_mir_borrowck(&infcx, input_body, promoted, None).0;
debug!("mir_borrowck done");
tcx.arena.alloc(opt_closure_req)
@@ -163,22 +152,22 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Bor
/// Perform the actual borrow checking.
///
-/// If `return_body_with_facts` is true, then return the body with non-erased
-/// region ids on which the borrow checking was performed together with Polonius
-/// facts.
-#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.with_opt_param().as_local().unwrap()), level = "debug")]
+/// Use `consumer_options: None` for the default behavior of returning
+/// [`BorrowCheckResult`] only. Otherwise, return [`BodyWithBorrowckFacts`] according
+/// to the given [`ConsumerOptions`].
+#[instrument(skip(infcx, input_body, input_promoted), fields(id=?input_body.source.def_id()), level = "debug")]
fn do_mir_borrowck<'tcx>(
infcx: &InferCtxt<'tcx>,
input_body: &Body<'tcx>,
input_promoted: &IndexSlice<Promoted, Body<'tcx>>,
- return_body_with_facts: bool,
+ consumer_options: Option<ConsumerOptions>,
) -> (BorrowCheckResult<'tcx>, Option<Box<BodyWithBorrowckFacts<'tcx>>>) {
- let def = input_body.source.with_opt_param().as_local().unwrap();
+ let def = input_body.source.def_id().expect_local();
debug!(?def);
let tcx = infcx.tcx;
let infcx = BorrowckInferCtxt::new(infcx);
- let param_env = tcx.param_env(def.did);
+ let param_env = tcx.param_env(def);
let mut local_names = IndexVec::from_elem(None, &input_body.local_decls);
for var_debug_info in &input_body.var_debug_info {
@@ -206,7 +195,7 @@ fn do_mir_borrowck<'tcx>(
errors.set_tainted_by_errors(e);
}
let upvars: Vec<_> = tcx
- .closure_captures(def.did)
+ .closure_captures(def)
.iter()
.map(|&captured_place| {
let capture = captured_place.info.capture_kind;
@@ -248,12 +237,10 @@ fn do_mir_borrowck<'tcx>(
.iterate_to_fixpoint()
.into_results_cursor(&body);
- let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def.did).is_fn_or_closure();
+ let locals_are_invalidated_at_exit = tcx.hir().body_owner_kind(def).is_fn_or_closure();
let borrow_set =
Rc::new(BorrowSet::build(tcx, body, locals_are_invalidated_at_exit, &mdpe.move_data));
- let use_polonius = return_body_with_facts || infcx.tcx.sess.opts.unstable_opts.polonius;
-
// Compute non-lexical lifetimes.
let nll::NllOutput {
regioncx,
@@ -273,7 +260,7 @@ fn do_mir_borrowck<'tcx>(
&mdpe.move_data,
&borrow_set,
&upvars,
- use_polonius,
+ consumer_options,
);
// Dump MIR results into a file, if that is enabled. This let us
@@ -342,7 +329,6 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators: Default::default(),
upvars: Vec::new(),
local_names: IndexVec::from_elem(None, &promoted_body.local_decls),
region_names: RefCell::default(),
@@ -371,7 +357,6 @@ fn do_mir_borrowck<'tcx>(
used_mut: Default::default(),
used_mut_upvars: SmallVec::new(),
borrow_set: Rc::clone(&borrow_set),
- dominators: Default::default(),
upvars,
local_names,
region_names: RefCell::default(),
@@ -455,13 +440,16 @@ fn do_mir_borrowck<'tcx>(
tainted_by_errors,
};
- let body_with_facts = if return_body_with_facts {
- let output_facts = mbcx.polonius_output.expect("Polonius output was not computed");
+ let body_with_facts = if consumer_options.is_some() {
+ let output_facts = mbcx.polonius_output;
Some(Box::new(BodyWithBorrowckFacts {
body: body_owned,
- input_facts: *polonius_input.expect("Polonius input facts were not generated"),
+ promoted,
+ borrow_set,
+ region_inference_context: regioncx,
+ location_table: polonius_input.as_ref().map(|_| location_table_owned),
+ input_facts: polonius_input,
output_facts,
- location_table: location_table_owned,
}))
} else {
None
@@ -472,22 +460,6 @@ fn do_mir_borrowck<'tcx>(
(result, body_with_facts)
}
-/// A `Body` with information computed by the borrow checker. This struct is
-/// intended to be consumed by compiler consumers.
-///
-/// We need to include the MIR body here because the region identifiers must
-/// match the ones in the Polonius facts.
-pub struct BodyWithBorrowckFacts<'tcx> {
- /// A mir body that contains region identifiers.
- pub body: Body<'tcx>,
- /// Polonius input facts.
- pub input_facts: AllFacts,
- /// Polonius output facts.
- pub output_facts: Rc<self::nll::PoloniusOutput>,
- /// The table that maps Polonius points to locations in the table.
- pub location_table: LocationTable,
-}
-
pub struct BorrowckInferCtxt<'cx, 'tcx> {
pub(crate) infcx: &'cx InferCtxt<'tcx>,
pub(crate) reg_var_to_origin: RefCell<FxIndexMap<ty::RegionVid, RegionCtxt>>,
@@ -509,11 +481,11 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
let next_region = self.infcx.next_region_var(origin);
let vid = next_region.as_var();
- if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
+ if cfg!(debug_assertions) {
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
let ctxt = get_ctxt_fn();
let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
- var_to_origin.insert(vid, ctxt);
+ assert_eq!(var_to_origin.insert(vid, ctxt), None);
}
next_region
@@ -528,14 +500,14 @@ impl<'cx, 'tcx> BorrowckInferCtxt<'cx, 'tcx> {
where
F: Fn() -> RegionCtxt,
{
- let next_region = self.infcx.next_nll_region_var(origin.clone());
+ let next_region = self.infcx.next_nll_region_var(origin);
let vid = next_region.as_var();
- if cfg!(debug_assertions) && !self.inside_canonicalization_ctxt() {
+ if cfg!(debug_assertions) {
debug!("inserting vid {:?} with origin {:?} into var_to_origin", vid, origin);
let ctxt = get_ctxt_fn();
let mut var_to_origin = self.reg_var_to_origin.borrow_mut();
- var_to_origin.insert(vid, ctxt);
+ assert_eq!(var_to_origin.insert(vid, ctxt), None);
}
next_region
@@ -602,9 +574,6 @@ struct MirBorrowckCtxt<'cx, 'tcx> {
/// The set of borrows extracted from the MIR
borrow_set: Rc<BorrowSet<'tcx>>,
- /// Dominators for MIR
- dominators: OnceCell<Dominators<BasicBlock>>,
-
/// Information about upvars not necessarily preserved in types or MIR
upvars: Vec<Upvar<'tcx>>,
@@ -676,7 +645,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
}
// Only relevant for mir typeck
StatementKind::AscribeUserType(..)
- // Only relevant for unsafeck
+ // Only relevant for liveness and unsafeck
| StatementKind::PlaceMention(..)
// Doesn't have any language semantics
| StatementKind::Coverage(..)
@@ -716,17 +685,19 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
TerminatorKind::SwitchInt { discr, targets: _ } => {
self.consume_operand(loc, (discr, span), flow_state);
}
- TerminatorKind::Drop { place, target: _, unwind: _ } => {
+ TerminatorKind::Drop { place, target: _, unwind: _, replace } => {
debug!(
"visit_terminator_drop \
loc: {:?} term: {:?} place: {:?} span: {:?}",
loc, term, place, span
);
+ let write_kind =
+ if *replace { WriteKind::Replace } else { WriteKind::StorageDeadOrDrop };
self.access_place(
loc,
(*place, span),
- (AccessDepth::Drop, Write(WriteKind::StorageDeadOrDrop)),
+ (AccessDepth::Drop, Write(write_kind)),
LocalMutationIsAllowed::Yes,
flow_state,
);
@@ -749,7 +720,7 @@ impl<'cx, 'tcx> rustc_mir_dataflow::ResultsVisitor<'cx, 'tcx> for MirBorrowckCtx
TerminatorKind::Assert { cond, expected: _, msg, target: _, unwind: _ } => {
self.consume_operand(loc, (cond, span), flow_state);
use rustc_middle::mir::AssertKind;
- if let AssertKind::BoundsCheck { len, index } = msg {
+ if let AssertKind::BoundsCheck { len, index } = &**msg {
self.consume_operand(loc, (len, span), flow_state);
self.consume_operand(loc, (index, span), flow_state);
}
@@ -916,6 +887,7 @@ enum ReadKind {
#[derive(Copy, Clone, PartialEq, Eq, Debug)]
enum WriteKind {
StorageDeadOrDrop,
+ Replace,
MutableBorrow(BorrowKind),
Mutate,
Move,
@@ -946,6 +918,7 @@ enum InitializationRequiringAction {
PartialAssignment,
}
+#[derive(Debug)]
struct RootPlace<'tcx> {
place_local: Local,
place_projection: &'tcx [PlaceElem<'tcx>],
@@ -1162,13 +1135,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
this.buffer_error(err);
}
WriteKind::StorageDeadOrDrop => this
- .report_storage_dead_or_drop_of_borrowed(location, place_span, borrow),
+ .report_borrowed_value_does_not_live_long_enough(
+ location,
+ borrow,
+ place_span,
+ Some(WriteKind::StorageDeadOrDrop),
+ ),
WriteKind::Mutate => {
this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
}
WriteKind::Move => {
this.report_move_out_while_borrowed(location, place_span, borrow)
}
+ WriteKind::Replace => {
+ this.report_illegal_mutation_of_borrowed(location, place_span, borrow)
+ }
}
Control::Break
}
@@ -1859,11 +1840,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// is allowed, remove this match arm.
ty::Adt(..) | ty::Tuple(..) => {
check_parent_of_field(self, location, place_base, span, flow_state);
-
- // rust-lang/rust#21232, #54499, #54986: during period where we reject
- // partial initialization, do not complain about unnecessary `mut` on
- // an attempt to do a partial initialization.
- self.used_mut.insert(place.local);
}
_ => {}
@@ -1951,6 +1927,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
(prefix, base, span),
mpi,
);
+
+ // rust-lang/rust#21232, #54499, #54986: during period where we reject
+ // partial initialization, do not complain about unnecessary `mut` on
+ // an attempt to do a partial initialization.
+ this.used_mut.insert(base.local);
}
}
}
@@ -2012,12 +1993,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
Reservation(
WriteKind::Move
+ | WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Shallow),
)
| Write(
WriteKind::Move
+ | WriteKind::Replace
| WriteKind::StorageDeadOrDrop
| WriteKind::MutableBorrow(BorrowKind::Shared)
| WriteKind::MutableBorrow(BorrowKind::Shallow),
@@ -2032,7 +2015,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
// been emitted (#52262).
self.infcx.tcx.sess.delay_span_bug(
span,
- &format!(
+ format!(
"Accessing `{:?}` with the kind `{:?}` shouldn't be possible",
place, kind,
),
@@ -2279,7 +2262,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> {
}
fn dominators(&self) -> &Dominators<BasicBlock> {
- self.dominators.get_or_init(|| self.body.basic_blocks.dominators())
+ // `BasicBlocks` computes dominators on-demand and caches them.
+ self.body.basic_blocks.dominators()
}
}
@@ -2393,7 +2377,7 @@ mod error {
}
for (_, (mut diag, count)) in std::mem::take(&mut self.errors.buffered_mut_errors) {
if count > 10 {
- diag.note(&format!("...and {} other attempted mutable borrows", count - 10));
+ diag.note(format!("...and {} other attempted mutable borrows", count - 10));
}
diag.buffer(&mut self.errors.buffered);
}
diff --git a/compiler/rustc_borrowck/src/location.rs b/compiler/rustc_borrowck/src/location.rs
index 288b7d85b..0e669abfd 100644
--- a/compiler/rustc_borrowck/src/location.rs
+++ b/compiler/rustc_borrowck/src/location.rs
@@ -1,6 +1,6 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::IndexVec;
use rustc_middle::mir::{BasicBlock, Body, Location};
/// Maps between a MIR Location, which identifies a particular
@@ -50,19 +50,19 @@ impl LocationTable {
}
pub fn all_points(&self) -> impl Iterator<Item = LocationIndex> {
- (0..self.num_points).map(LocationIndex::new)
+ (0..self.num_points).map(LocationIndex::from_usize)
}
pub fn start_index(&self, location: Location) -> LocationIndex {
let Location { block, statement_index } = location;
let start_index = self.statements_before_block[block];
- LocationIndex::new(start_index + statement_index * 2)
+ LocationIndex::from_usize(start_index + statement_index * 2)
}
pub fn mid_index(&self, location: Location) -> LocationIndex {
let Location { block, statement_index } = location;
let start_index = self.statements_before_block[block];
- LocationIndex::new(start_index + statement_index * 2 + 1)
+ LocationIndex::from_usize(start_index + statement_index * 2 + 1)
}
pub fn to_location(&self, index: LocationIndex) -> RichLocation {
diff --git a/compiler/rustc_borrowck/src/member_constraints.rs b/compiler/rustc_borrowck/src/member_constraints.rs
index f637e6a95..842e90080 100644
--- a/compiler/rustc_borrowck/src/member_constraints.rs
+++ b/compiler/rustc_borrowck/src/member_constraints.rs
@@ -2,7 +2,7 @@
#![deny(rustc::diagnostic_outside_of_impl)]
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxIndexMap;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::infer::MemberConstraint;
use rustc_middle::ty::{self, Ty};
use rustc_span::Span;
@@ -221,7 +221,7 @@ fn append_list(
) {
let mut p = target_list;
loop {
- let mut r = &mut constraints[p];
+ let r = &mut constraints[p];
match r.next_constraint {
Some(q) => p = q,
None => {
diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs
index 59a3ab318..889acb3ac 100644
--- a/compiler/rustc_borrowck/src/nll.rs
+++ b/compiler/rustc_borrowck/src/nll.rs
@@ -4,11 +4,11 @@
use rustc_data_structures::fx::FxIndexMap;
use rustc_hir::def_id::LocalDefId;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::mir::{create_dump_file, dump_enabled, dump_mir, PassWhere};
use rustc_middle::mir::{
- BasicBlock, Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location,
- Promoted,
+ Body, ClosureOutlivesSubject, ClosureRegionRequirements, LocalKind, Location, Promoted,
+ START_BLOCK,
};
use rustc_middle::ty::{self, OpaqueHiddenType, TyCtxt};
use rustc_span::symbol::sym;
@@ -27,6 +27,7 @@ use rustc_mir_dataflow::ResultsCursor;
use crate::{
borrow_set::BorrowSet,
constraint_generation,
+ consumers::ConsumerOptions,
diagnostics::RegionErrors,
facts::{AllFacts, AllFactsExt, RustcFacts},
invalidation,
@@ -61,7 +62,7 @@ pub(crate) fn replace_regions_in_mir<'tcx>(
body: &mut Body<'tcx>,
promoted: &mut IndexSlice<Promoted, Body<'tcx>>,
) -> UniversalRegions<'tcx> {
- let def = body.source.with_opt_param().as_local().unwrap();
+ let def = body.source.def_id().expect_local();
debug!(?def);
@@ -94,8 +95,8 @@ fn populate_polonius_move_facts(
}
}
- let fn_entry_start = location_table
- .start_index(Location { block: BasicBlock::from_u32(0u32), statement_index: 0 });
+ let fn_entry_start =
+ location_table.start_index(Location { block: START_BLOCK, statement_index: 0 });
// initialized_at
for init in move_data.inits.iter() {
@@ -165,10 +166,14 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
move_data: &MoveData<'tcx>,
borrow_set: &BorrowSet<'tcx>,
upvars: &[Upvar<'tcx>],
- use_polonius: bool,
+ consumer_options: Option<ConsumerOptions>,
) -> NllOutput<'tcx> {
+ let polonius_input = consumer_options.map(|c| c.polonius_input()).unwrap_or_default()
+ || infcx.tcx.sess.opts.unstable_opts.polonius;
+ let polonius_output = consumer_options.map(|c| c.polonius_output()).unwrap_or_default()
+ || infcx.tcx.sess.opts.unstable_opts.polonius;
let mut all_facts =
- (use_polonius || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
+ (polonius_input || AllFacts::enabled(infcx.tcx)).then_some(AllFacts::default());
let universal_regions = Rc::new(universal_regions);
@@ -189,7 +194,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
move_data,
elements,
upvars,
- use_polonius,
+ polonius_input,
);
if let Some(all_facts) = &mut all_facts {
@@ -235,7 +240,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
// Create the region inference context, taking ownership of the
// region inference data that was contained in `infcx`, and the
// base constraints generated by the type-check.
- let var_origins = infcx.take_region_var_origins();
+ let var_origins = infcx.get_region_var_origins();
let MirTypeckRegionConstraints {
placeholder_indices,
placeholder_index_to_region: _,
@@ -284,7 +289,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
all_facts.write_to_dir(dir_path, location_table).unwrap();
}
- if use_polonius {
+ if polonius_output {
let algorithm =
env::var("POLONIUS_ALGORITHM").unwrap_or_else(|_| String::from("Hybrid"));
let algorithm = Algorithm::from_str(&algorithm).unwrap();
@@ -399,7 +404,7 @@ pub(super) fn dump_annotation<'tcx>(
regioncx.annotate(tcx, &mut err);
- err.note(&format!(
+ err.note(format!(
"number of external vids: {}",
closure_region_requirements.num_external_vids
));
@@ -421,7 +426,7 @@ pub(super) fn dump_annotation<'tcx>(
};
if !opaque_type_values.is_empty() {
- err.note(&format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
+ err.note(format!("Inferred opaque type values:\n{:#?}", opaque_type_values));
}
errors.buffer_non_error_diag(err);
@@ -430,7 +435,7 @@ pub(super) fn dump_annotation<'tcx>(
fn for_each_region_constraint<'tcx>(
tcx: TyCtxt<'tcx>,
closure_region_requirements: &ClosureRegionRequirements<'tcx>,
- with_msg: &mut dyn FnMut(&str) -> io::Result<()>,
+ with_msg: &mut dyn FnMut(String) -> io::Result<()>,
) -> io::Result<()> {
for req in &closure_region_requirements.outlives_requirements {
let subject = match req.subject {
@@ -439,7 +444,7 @@ fn for_each_region_constraint<'tcx>(
format!("{:?}", ty.instantiate(tcx, |vid| tcx.mk_re_var(vid)))
}
};
- with_msg(&format!("where {}: {:?}", subject, req.outlived_free_region,))?;
+ with_msg(format!("where {}: {:?}", subject, req.outlived_free_region,))?;
}
Ok(())
}
diff --git a/compiler/rustc_borrowck/src/place_ext.rs b/compiler/rustc_borrowck/src/place_ext.rs
index 85d207b2f..d521d0db2 100644
--- a/compiler/rustc_borrowck/src/place_ext.rs
+++ b/compiler/rustc_borrowck/src/place_ext.rs
@@ -7,7 +7,7 @@ use rustc_middle::mir::{Body, Mutability, Place};
use rustc_middle::ty::{self, TyCtxt};
/// Extension methods for the `Place` type.
-pub(crate) trait PlaceExt<'tcx> {
+pub trait PlaceExt<'tcx> {
/// Returns `true` if we can safely ignore borrows of this place.
/// This is true whenever there is no action that the user can do
/// to the place `self` that would invalidate the borrow. This is true
diff --git a/compiler/rustc_borrowck/src/places_conflict.rs b/compiler/rustc_borrowck/src/places_conflict.rs
index 918fb2d69..25c485b81 100644
--- a/compiler/rustc_borrowck/src/places_conflict.rs
+++ b/compiler/rustc_borrowck/src/places_conflict.rs
@@ -16,7 +16,7 @@ use std::iter;
/// being run in the calling context, the conservative choice is to assume the compared indices
/// are disjoint (and therefore, do not overlap).
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
-pub(crate) enum PlaceConflictBias {
+pub enum PlaceConflictBias {
Overlap,
NoOverlap,
}
@@ -24,7 +24,7 @@ pub(crate) enum PlaceConflictBias {
/// Helper function for checking if places conflict with a mutable borrow and deep access depth.
/// This is used to check for places conflicting outside of the borrow checking code (such as in
/// dataflow).
-pub(crate) fn places_conflict<'tcx>(
+pub fn places_conflict<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
borrow_place: Place<'tcx>,
diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs
index 729f3dbff..50b246b14 100644
--- a/compiler/rustc_borrowck/src/region_infer/mod.rs
+++ b/compiler/rustc_borrowck/src/region_infer/mod.rs
@@ -7,12 +7,12 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::CRATE_DEF_ID;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
use rustc_infer::infer::{InferCtxt, NllRegionVariableOrigin, RegionVariableOrigin};
use rustc_middle::mir::{
- Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
+ BasicBlock, Body, ClosureOutlivesRequirement, ClosureOutlivesSubject, ClosureOutlivesSubjectTy,
ClosureRegionRequirements, ConstraintCategory, Local, Location, ReturnConstraint,
TerminatorKind,
};
@@ -76,7 +76,7 @@ pub struct RegionInferenceContext<'tcx> {
/// Reverse of the SCC constraint graph -- i.e., an edge `A -> B` exists if
/// `B: A`. This is used to compute the universal regions that are required
/// to outlive a given SCC. Computed lazily.
- rev_scc_graph: Option<Rc<ReverseSccGraph>>,
+ rev_scc_graph: Option<ReverseSccGraph>,
/// The "R0 member of [R1..Rn]" constraints, indexed by SCC.
member_constraints: Rc<MemberConstraintSet<'tcx, ConstraintSccIndex>>,
@@ -585,6 +585,11 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.universal_regions.to_region_vid(r)
}
+ /// Returns an iterator over all the outlives constraints.
+ pub fn outlives_constraints(&self) -> impl Iterator<Item = OutlivesConstraint<'tcx>> + '_ {
+ self.constraints.outlives().iter().copied()
+ }
+
/// Adds annotations for `#[rustc_regions]`; see `UniversalRegions::annotate`.
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
self.universal_regions.annotate(tcx, err)
@@ -598,6 +603,20 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.scc_values.contains(scc, p)
}
+ /// Returns the lowest statement index in `start..=end` which is not contained by `r`.
+ ///
+ /// Panics if called before `solve()` executes.
+ pub(crate) fn first_non_contained_inclusive(
+ &self,
+ r: RegionVid,
+ block: BasicBlock,
+ start: usize,
+ end: usize,
+ ) -> Option<usize> {
+ let scc = self.constraint_sccs.scc(r);
+ self.scc_values.first_non_contained_inclusive(scc, block, start, end)
+ }
+
/// Returns access to the value of `r` for debugging purposes.
pub(crate) fn region_value_str(&self, r: RegionVid) -> String {
let scc = self.constraint_sccs.scc(r);
@@ -698,7 +717,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
#[instrument(skip(self, _body), level = "debug")]
fn propagate_constraints(&mut self, _body: &Body<'tcx>) {
debug!("constraints={:#?}", {
- let mut constraints: Vec<_> = self.constraints.outlives().iter().collect();
+ let mut constraints: Vec<_> = self.outlives_constraints().collect();
constraints.sort_by_key(|c| (c.sup, c.sub));
constraints
.into_iter()
@@ -813,9 +832,9 @@ impl<'tcx> RegionInferenceContext<'tcx> {
// free region that must outlive the member region `R0` (`UB:
// R0`). Therefore, we need only keep an option `O` if `UB: O`
// for all UB.
- let rev_scc_graph = self.reverse_scc_graph();
+ self.compute_reverse_scc_graph();
let universal_region_relations = &self.universal_region_relations;
- for ub in rev_scc_graph.upper_bounds(scc) {
+ for ub in self.rev_scc_graph.as_ref().unwrap().upper_bounds(scc) {
debug!(?ub);
choice_regions.retain(|&o_r| universal_region_relations.outlives(ub, o_r));
}
diff --git a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
index 2b16655cf..7fc89e89a 100644
--- a/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
+++ b/compiler/rustc_borrowck/src/region_infer/opaque_types.rs
@@ -2,9 +2,10 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_errors::ErrorGuaranteed;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::OpaqueTyOrigin;
+use rustc_infer::infer::InferCtxt;
use rustc_infer::infer::TyCtxtInferExt as _;
-use rustc_infer::infer::{DefiningAnchor, InferCtxt};
use rustc_infer::traits::{Obligation, ObligationCause};
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, OpaqueHiddenType, OpaqueTypeKey, Ty, TyCtxt, TypeFoldable};
@@ -152,8 +153,10 @@ impl<'tcx> RegionInferenceContext<'tcx> {
let guar = ty.error_reported().err().unwrap_or_else(|| {
prev.report_mismatch(
&OpaqueHiddenType { ty, span: concrete_type.span },
+ opaque_type_key.def_id,
infcx.tcx,
)
+ .emit()
});
prev.ty = infcx.tcx.ty_error(guar);
}
@@ -265,7 +268,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
// Only check this for TAIT. RPIT already supports `tests/ui/impl-trait/nested-return-type2.rs`
// on stable and we'd break that.
- let OpaqueTyOrigin::TyAlias = origin else {
+ let OpaqueTyOrigin::TyAlias { .. } = origin else {
return definition_ty;
};
let def_id = opaque_type_key.def_id;
@@ -360,7 +363,7 @@ fn check_opaque_type_parameter_valid(
// which would error here on all of the `'static` args.
OpaqueTyOrigin::FnReturn(..) | OpaqueTyOrigin::AsyncFn(..) => return Ok(()),
// Check these
- OpaqueTyOrigin::TyAlias => {}
+ OpaqueTyOrigin::TyAlias { .. } => {}
}
let opaque_generics = tcx.generics_of(opaque_type_key.def_id);
let mut seen_params: FxIndexMap<_, Vec<_>> = FxIndexMap::default();
@@ -399,7 +402,7 @@ fn check_opaque_type_parameter_valid(
return Err(tcx
.sess
.struct_span_err(span, "non-defining opaque type use in defining scope")
- .span_note(spans, &format!("{} used multiple times", descr))
+ .span_note(spans, format!("{} used multiple times", descr))
.emit());
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
index 23a59c128..fe56bd54a 100644
--- a/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
+++ b/compiler/rustc_borrowck/src/region_infer/reverse_sccs.rs
@@ -8,7 +8,6 @@ use rustc_data_structures::graph::vec_graph::VecGraph;
use rustc_data_structures::graph::WithSuccessors;
use rustc_middle::ty::RegionVid;
use std::ops::Range;
-use std::rc::Rc;
pub(crate) struct ReverseSccGraph {
graph: VecGraph<ConstraintSccIndex>,
@@ -40,10 +39,10 @@ impl ReverseSccGraph {
}
impl RegionInferenceContext<'_> {
- /// Compute and return the reverse SCC-based constraint graph (lazily).
- pub(super) fn reverse_scc_graph(&mut self) -> Rc<ReverseSccGraph> {
- if let Some(g) = &self.rev_scc_graph {
- return g.clone();
+ /// Compute the reverse SCC-based constraint graph (lazily).
+ pub(super) fn compute_reverse_scc_graph(&mut self) {
+ if self.rev_scc_graph.is_some() {
+ return;
}
let graph = self.constraint_sccs.reverse();
@@ -63,8 +62,6 @@ impl RegionInferenceContext<'_> {
start += group_size;
}
- let rev_graph = Rc::new(ReverseSccGraph { graph, scc_regions, universal_regions });
- self.rev_scc_graph = Some(rev_graph.clone());
- rev_graph
+ self.rev_scc_graph = Some(ReverseSccGraph { graph, scc_regions, universal_regions });
}
}
diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs
index 8132800f1..9290e7479 100644
--- a/compiler/rustc_borrowck/src/region_infer/values.rs
+++ b/compiler/rustc_borrowck/src/region_infer/values.rs
@@ -4,8 +4,8 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::interval::IntervalSet;
use rustc_index::interval::SparseIntervalMatrix;
-use rustc_index::vec::Idx;
-use rustc_index::vec::IndexVec;
+use rustc_index::Idx;
+use rustc_index::IndexVec;
use rustc_middle::mir::{BasicBlock, Body, Location};
use rustc_middle::ty::{self, RegionVid};
use std::fmt::Debug;
@@ -159,7 +159,7 @@ impl<N: Idx> LivenessValues<N> {
/// Returns `true` if the region `r` contains the given element.
pub(crate) fn contains(&self, row: N, location: Location) -> bool {
let index = self.elements.point_from_location(location);
- self.points.row(row).map_or(false, |r| r.contains(index))
+ self.points.row(row).is_some_and(|r| r.contains(index))
}
/// Returns an iterator of all the elements contained by the region `r`
@@ -283,6 +283,22 @@ impl<N: Idx> RegionValues<N> {
elem.contained_in_row(self, r)
}
+ /// Returns the lowest statement index in `start..=end` which is not contained by `r`.
+ pub(crate) fn first_non_contained_inclusive(
+ &self,
+ r: N,
+ block: BasicBlock,
+ start: usize,
+ end: usize,
+ ) -> Option<usize> {
+ let row = self.points.row(r)?;
+ let block = self.elements.entry_point(block);
+ let start = block.plus(start);
+ let end = block.plus(end);
+ let first_unset = row.first_unset_in(start..=end)?;
+ Some(first_unset.index() - block.index())
+ }
+
/// `self[to] |= values[from]`, essentially: that is, take all the
/// elements for the region `from` from `values` and add them to
/// the region `to` in `self`.
diff --git a/compiler/rustc_borrowck/src/renumber.rs b/compiler/rustc_borrowck/src/renumber.rs
index 94ce29dfe..4389d2b60 100644
--- a/compiler/rustc_borrowck/src/renumber.rs
+++ b/compiler/rustc_borrowck/src/renumber.rs
@@ -1,7 +1,7 @@
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
use crate::BorrowckInferCtxt;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::mir::visit::{MutVisitor, TyContext};
use rustc_middle::mir::Constant;
@@ -109,6 +109,14 @@ impl<'a, 'tcx> MutVisitor<'tcx> for RegionRenumberer<'a, 'tcx> {
}
#[instrument(skip(self), level = "debug")]
+ fn visit_ty_const(&mut self, ct: &mut ty::Const<'tcx>, location: Location) {
+ let old_ct = *ct;
+ *ct = self.renumber_regions(old_ct, || RegionCtxt::Location(location));
+
+ debug!(?ct);
+ }
+
+ #[instrument(skip(self), level = "debug")]
fn visit_constant(&mut self, constant: &mut Constant<'tcx>, location: Location) {
let literal = constant.literal;
constant.literal = self.renumber_regions(literal, || RegionCtxt::Location(location));
diff --git a/compiler/rustc_borrowck/src/session_diagnostics.rs b/compiler/rustc_borrowck/src/session_diagnostics.rs
index a36789290..fceae5bb3 100644
--- a/compiler/rustc_borrowck/src/session_diagnostics.rs
+++ b/compiler/rustc_borrowck/src/session_diagnostics.rs
@@ -184,7 +184,7 @@ pub(crate) enum CaptureVarPathUseCause {
#[derive(Subdiagnostic)]
pub(crate) enum CaptureVarKind {
#[label(borrowck_capture_immute)]
- Immute {
+ Immut {
#[primary_span]
kind_span: Span,
},
@@ -204,16 +204,80 @@ pub(crate) enum CaptureVarKind {
pub(crate) enum CaptureVarCause {
#[label(borrowck_var_borrow_by_use_place_in_generator)]
BorrowUsePlaceGenerator {
+ is_single_var: bool,
place: String,
#[primary_span]
var_span: Span,
},
#[label(borrowck_var_borrow_by_use_place_in_closure)]
BorrowUsePlaceClosure {
+ is_single_var: bool,
place: String,
#[primary_span]
var_span: Span,
},
+ #[label(borrowck_var_borrow_by_use_in_generator)]
+ BorrowUseInGenerator {
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_borrow_by_use_in_closure)]
+ BorrowUseInClosure {
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_move_by_use_in_generator)]
+ MoveUseInGenerator {
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_move_by_use_in_closure)]
+ MoveUseInClosure {
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_first_borrow_by_use_place_in_generator)]
+ FirstBorrowUsePlaceGenerator {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_first_borrow_by_use_place_in_closure)]
+ FirstBorrowUsePlaceClosure {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_second_borrow_by_use_place_in_generator)]
+ SecondBorrowUsePlaceGenerator {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_second_borrow_by_use_place_in_closure)]
+ SecondBorrowUsePlaceClosure {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_var_mutable_borrow_by_use_place_in_closure)]
+ MutableBorrowUsePlaceClosure {
+ place: String,
+ #[primary_span]
+ var_span: Span,
+ },
+ #[label(borrowck_partial_var_move_by_use_in_generator)]
+ PartialMoveUseInGenerator {
+ #[primary_span]
+ var_span: Span,
+ is_partial: bool,
+ },
+ #[label(borrowck_partial_var_move_by_use_in_closure)]
+ PartialMoveUseInClosure {
+ #[primary_span]
+ var_span: Span,
+ is_partial: bool,
+ },
}
#[derive(Diagnostic)]
@@ -239,3 +303,152 @@ pub(crate) struct NonGenericOpaqueTypeParam<'a, 'tcx> {
#[label]
pub param_span: Span,
}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonLabel<'a> {
+ #[label(borrowck_moved_due_to_call)]
+ Call {
+ #[primary_span]
+ fn_call_span: Span,
+ place_name: &'a str,
+ is_partial: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_moved_due_to_usage_in_operator)]
+ OperatorUse {
+ #[primary_span]
+ fn_call_span: Span,
+ place_name: &'a str,
+ is_partial: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_moved_due_to_implicit_into_iter_call)]
+ ImplicitCall {
+ #[primary_span]
+ fn_call_span: Span,
+ place_name: &'a str,
+ is_partial: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_moved_due_to_method_call)]
+ MethodCall {
+ #[primary_span]
+ fn_call_span: Span,
+ place_name: &'a str,
+ is_partial: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_moved_due_to_await)]
+ Await {
+ #[primary_span]
+ fn_call_span: Span,
+ place_name: &'a str,
+ is_partial: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_value_moved_here)]
+ MovedHere {
+ #[primary_span]
+ move_span: Span,
+ is_partial: bool,
+ is_move_msg: bool,
+ is_loop_message: bool,
+ },
+ #[label(borrowck_consider_borrow_type_contents)]
+ BorrowContent {
+ #[primary_span]
+ var_span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonNote {
+ #[note(borrowck_moved_a_fn_once_in_call)]
+ FnOnceMoveInCall {
+ #[primary_span]
+ var_span: Span,
+ },
+ #[note(borrowck_calling_operator_moves_lhs)]
+ LhsMoveByOperator {
+ #[primary_span]
+ span: Span,
+ },
+ #[note(borrowck_func_take_self_moved_place)]
+ FuncTakeSelf {
+ func: String,
+ place_name: String,
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureReasonSuggest<'tcx> {
+ #[suggestion(
+ borrowck_suggest_iterate_over_slice,
+ applicability = "maybe-incorrect",
+ code = "&",
+ style = "verbose"
+ )]
+ IterateSlice {
+ ty: Ty<'tcx>,
+ #[primary_span]
+ span: Span,
+ },
+ #[suggestion(
+ borrowck_suggest_create_freash_reborrow,
+ applicability = "maybe-incorrect",
+ code = "as_mut().",
+ style = "verbose"
+ )]
+ FreshReborrow {
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum CaptureArgLabel {
+ #[label(borrowck_value_capture_here)]
+ Capture {
+ is_within: bool,
+ #[primary_span]
+ args_span: Span,
+ },
+ #[label(borrowck_move_out_place_here)]
+ MoveOutPlace {
+ place: String,
+ #[primary_span]
+ args_span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum OnClosureNote<'a> {
+ #[note(borrowck_closure_invoked_twice)]
+ InvokedTwice {
+ place_name: &'a str,
+ #[primary_span]
+ span: Span,
+ },
+ #[note(borrowck_closure_moved_twice)]
+ MovedTwice {
+ place_name: &'a str,
+ #[primary_span]
+ span: Span,
+ },
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum TypeNoCopy<'a, 'tcx> {
+ #[label(borrowck_ty_no_impl_copy)]
+ Label {
+ is_partial_move: bool,
+ ty: Ty<'tcx>,
+ place: &'a str,
+ #[primary_span]
+ span: Span,
+ },
+ #[note(borrowck_ty_no_impl_copy)]
+ Note { is_partial_move: bool, ty: Ty<'tcx>, place: &'a str },
+}
diff --git a/compiler/rustc_borrowck/src/type_check/canonical.rs b/compiler/rustc_borrowck/src/type_check/canonical.rs
index b27d5d205..f527eee7b 100644
--- a/compiler/rustc_borrowck/src/type_check/canonical.rs
+++ b/compiler/rustc_borrowck/src/type_check/canonical.rs
@@ -1,13 +1,13 @@
use std::fmt;
-use rustc_infer::infer::{canonical::Canonical, InferOk};
+use rustc_errors::ErrorGuaranteed;
+use rustc_infer::infer::canonical::Canonical;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable};
use rustc_span::def_id::DefId;
use rustc_span::Span;
use rustc_trait_selection::traits::query::type_op::{self, TypeOpOutput};
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
-use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
+use rustc_trait_selection::traits::ObligationCause;
use crate::diagnostics::{ToUniverseInfo, UniverseInfo};
@@ -30,14 +30,15 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
locations: Locations,
category: ConstraintCategory<'tcx>,
op: Op,
- ) -> Fallible<R>
+ ) -> Result<R, ErrorGuaranteed>
where
Op: type_op::TypeOp<'tcx, Output = R>,
Op::ErrorInfo: ToUniverseInfo<'tcx>,
{
let old_universe = self.infcx.universe();
- let TypeOpOutput { output, constraints, error_info } = op.fully_perform(self.infcx)?;
+ let TypeOpOutput { output, constraints, error_info } =
+ op.fully_perform(self.infcx, locations.span(self.body))?;
debug!(?output, ?constraints);
@@ -135,14 +136,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
) {
let param_env = self.param_env;
let predicate = predicate.to_predicate(self.tcx());
- self.fully_perform_op(
+ let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
locations,
category,
param_env.and(type_op::prove_predicate::ProvePredicate::new(predicate)),
- )
- .unwrap_or_else(|NoSolution| {
- span_mirbug!(self, NoSolution, "could not prove {:?}", predicate);
- })
+ );
}
pub(super) fn normalize<T>(&mut self, value: T, location: impl NormalizeLocation) -> T
@@ -163,15 +161,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
T: type_op::normalize::Normalizable<'tcx> + fmt::Display + Copy + 'tcx,
{
let param_env = self.param_env;
- self.fully_perform_op(
+ let result: Result<_, ErrorGuaranteed> = self.fully_perform_op(
location.to_locations(),
category,
param_env.and(type_op::normalize::Normalize::new(value)),
- )
- .unwrap_or_else(|NoSolution| {
- span_mirbug!(self, NoSolution, "failed to normalize `{:?}`", value);
- value
- })
+ );
+ result.unwrap_or(value)
}
#[instrument(skip(self), level = "debug")]
@@ -181,18 +176,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
user_ty: ty::UserType<'tcx>,
span: Span,
) {
- self.fully_perform_op(
+ let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
Locations::All(span),
ConstraintCategory::Boring,
self.param_env.and(type_op::ascribe_user_type::AscribeUserType::new(mir_ty, user_ty)),
- )
- .unwrap_or_else(|err| {
- span_mirbug!(
- self,
- span,
- "ascribe_user_type `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
- );
- });
+ );
}
/// *Incorrectly* skips the WF checks we normally do in `ascribe_user_type`.
@@ -219,27 +207,17 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
let cause = ObligationCause::dummy_with_span(span);
let param_env = self.param_env;
- let op = |infcx: &'_ _| {
- let ocx = ObligationCtxt::new_in_snapshot(infcx);
- let user_ty = ocx.normalize(&cause, param_env, user_ty);
- ocx.eq(&cause, param_env, user_ty, mir_ty)?;
- if !ocx.select_all_or_error().is_empty() {
- return Err(NoSolution);
- }
- Ok(InferOk { value: (), obligations: vec![] })
- };
-
- self.fully_perform_op(
+ let _: Result<_, ErrorGuaranteed> = self.fully_perform_op(
Locations::All(span),
ConstraintCategory::Boring,
- type_op::custom::CustomTypeOp::new(op, || "ascribe_user_type_skip_wf".to_string()),
- )
- .unwrap_or_else(|err| {
- span_mirbug!(
- self,
- span,
- "ascribe_user_type_skip_wf `{mir_ty:?}=={user_ty:?}` failed with `{err:?}`",
- );
- });
+ type_op::custom::CustomTypeOp::new(
+ |ocx| {
+ let user_ty = ocx.normalize(&cause, param_env, user_ty);
+ ocx.eq(&cause, param_env, user_ty, mir_ty)?;
+ Ok(())
+ },
+ "ascribe_user_type_skip_wf",
+ ),
+ );
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
index 4004966c4..c8ec1257d 100644
--- a/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
+++ b/compiler/rustc_borrowck/src/type_check/free_region_relations.rs
@@ -8,7 +8,7 @@ use rustc_infer::infer::InferCtxt;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::traits::query::OutlivesBound;
use rustc_middle::ty::{self, RegionVid, Ty};
-use rustc_span::Span;
+use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::traits::query::type_op::{self, TypeOp};
use std::rc::Rc;
use type_op::TypeOpOutput;
@@ -243,18 +243,11 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let TypeOpOutput { output: norm_ty, constraints: constraints_normalize, .. } = self
.param_env
.and(type_op::normalize::Normalize::new(ty))
- .fully_perform(self.infcx)
- .unwrap_or_else(|_| {
- let guar = self
- .infcx
- .tcx
- .sess
- .delay_span_bug(span, &format!("failed to normalize {:?}", ty));
- TypeOpOutput {
- output: self.infcx.tcx.ty_error(guar),
- constraints: None,
- error_info: None,
- }
+ .fully_perform(self.infcx, span)
+ .unwrap_or_else(|guar| TypeOpOutput {
+ output: self.infcx.tcx.ty_error(guar),
+ constraints: None,
+ error_info: None,
});
if let Some(c) = constraints_normalize {
constraints.push(c)
@@ -324,7 +317,7 @@ impl<'tcx> UniversalRegionRelationsBuilder<'_, 'tcx> {
let TypeOpOutput { output: bounds, constraints, .. } = self
.param_env
.and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
- .fully_perform(self.infcx)
+ .fully_perform(self.infcx, DUMMY_SP)
.unwrap_or_else(|_| bug!("failed to compute implied bounds {:?}", ty));
debug!(?bounds, ?constraints);
self.add_outlives_bounds(bounds);
diff --git a/compiler/rustc_borrowck/src/type_check/input_output.rs b/compiler/rustc_borrowck/src/type_check/input_output.rs
index 17e702eb8..a06d4bcc6 100644
--- a/compiler/rustc_borrowck/src/type_check/input_output.rs
+++ b/compiler/rustc_borrowck/src/type_check/input_output.rs
@@ -7,7 +7,6 @@
//! `RETURN_PLACE` the MIR arguments) are always fully normalized (and
//! contain revealed `impl Trait` values).
-use rustc_index::vec::Idx;
use rustc_infer::infer::LateBoundRegionConversionTime;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty};
@@ -83,7 +82,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
// In MIR, argument N is stored in local N+1.
- let local = Local::new(argument_index + 1);
+ let local = Local::from_usize(argument_index + 1);
let mir_input_ty = body.local_decls[local].ty;
@@ -107,7 +106,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if body.yield_ty().is_some() != universal_regions.yield_ty.is_some() {
self.tcx().sess.delay_span_bug(
body.span,
- &format!(
+ format!(
"Expected body to have yield_ty ({:?}) iff we have a UR yield_ty ({:?})",
body.yield_ty(),
universal_regions.yield_ty,
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
index 2c387edfe..a9ca94567 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/local_use_map.rs
@@ -1,5 +1,5 @@
use rustc_data_structures::vec_linked_list as vll;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::{Body, Local, Location};
diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
index 9731b10aa..eb02604b9 100644
--- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
+++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs
@@ -3,8 +3,9 @@ use rustc_index::bit_set::HybridBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
+use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
-use rustc_trait_selection::traits::query::dropck_outlives::DropckOutlivesResult;
+use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
use std::rc::Rc;
@@ -568,10 +569,15 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
) -> DropData<'tcx> {
debug!("compute_drop_data(dropped_ty={:?})", dropped_ty,);
- let param_env = typeck.param_env;
- let TypeOpOutput { output, constraints, .. } =
- param_env.and(DropckOutlives::new(dropped_ty)).fully_perform(typeck.infcx).unwrap();
-
- DropData { dropck_result: output, region_constraint_data: constraints }
+ match typeck
+ .param_env
+ .and(DropckOutlives::new(dropped_ty))
+ .fully_perform(typeck.infcx, DUMMY_SP)
+ {
+ Ok(TypeOpOutput { output, constraints, .. }) => {
+ DropData { dropck_result: output, region_constraint_data: constraints }
+ }
+ Err(_) => DropData { dropck_result: Default::default(), region_constraint_data: None },
+ }
}
}
diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs
index 2f10e30be..dc5121e1a 100644
--- a/compiler/rustc_borrowck/src/type_check/mod.rs
+++ b/compiler/rustc_borrowck/src/type_check/mod.rs
@@ -10,22 +10,24 @@ use either::Either;
use hir::OpaqueTyOrigin;
use rustc_data_structures::frozen::Frozen;
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
+use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::lang_items::LangItem;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::env::RegionBoundPairs;
use rustc_infer::infer::region_constraints::RegionConstraintData;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
- InferCtxt, InferOk, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
+ InferCtxt, LateBoundRegion, LateBoundRegionConversionTime, NllRegionVariableOrigin,
};
use rustc_middle::mir::tcx::PlaceTy;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::AssertKind;
use rustc_middle::mir::*;
+use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{SubstsRef, UserSubsts};
@@ -41,13 +43,14 @@ use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use rustc_trait_selection::traits::query::type_op::custom::scrape_region_constraints;
use rustc_trait_selection::traits::query::type_op::custom::CustomTypeOp;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
-use rustc_trait_selection::traits::query::Fallible;
+
use rustc_trait_selection::traits::PredicateObligation;
use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::MoveData;
use rustc_mir_dataflow::ResultsCursor;
+use crate::renumber::RegionCtxt;
use crate::session_diagnostics::MoveUnsized;
use crate::{
borrow_set::BorrowSet,
@@ -71,7 +74,7 @@ macro_rules! span_mirbug {
$crate::type_check::mirbug(
$context.tcx(),
$context.last_span,
- &format!(
+ format!(
"broken MIR in {:?} ({:?}): {}",
$context.body().source.def_id(),
$elem,
@@ -183,17 +186,19 @@ pub(crate) fn type_check<'mir, 'tcx>(
&mut borrowck_context,
);
- let errors_reported = {
- let mut verifier = TypeVerifier::new(&mut checker, promoted);
- verifier.visit_body(&body);
- verifier.errors_reported
- };
-
- if !errors_reported {
- // if verifier failed, don't do further checks to avoid ICEs
- checker.typeck_mir(body);
+ // FIXME(-Ztrait-solver=next): A bit dubious that we're only registering
+ // predefined opaques in the typeck root.
+ // FIXME(-Ztrait-solver=next): This is also totally wrong for TAITs, since
+ // the HIR typeck map defining usages back to their definition params,
+ // they won't actually match up with the usages in this body...
+ if infcx.tcx.trait_solver_next() && !infcx.tcx.is_typeck_child(body.source.def_id()) {
+ checker.register_predefined_opaques_in_new_solver();
}
+ let mut verifier = TypeVerifier::new(&mut checker, promoted);
+ verifier.visit_body(&body);
+
+ checker.typeck_mir(body);
checker.equate_inputs_and_outputs(&body, universal_regions, &normalized_inputs_and_output);
checker.check_signature_annotation(&body);
@@ -213,30 +218,28 @@ pub(crate) fn type_check<'mir, 'tcx>(
let opaque_type_values = opaque_type_values
.into_iter()
.map(|(opaque_type_key, decl)| {
- checker
- .fully_perform_op(
- Locations::All(body.span),
- ConstraintCategory::OpaqueType,
- CustomTypeOp::new(
- |infcx| {
- infcx.register_member_constraints(
- param_env,
- opaque_type_key,
- decl.hidden_type.ty,
- decl.hidden_type.span,
- );
- Ok(InferOk { value: (), obligations: vec![] })
- },
- || "opaque_type_map".to_string(),
- ),
- )
- .unwrap();
+ let _: Result<_, ErrorGuaranteed> = checker.fully_perform_op(
+ Locations::All(body.span),
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |ocx| {
+ ocx.infcx.register_member_constraints(
+ param_env,
+ opaque_type_key,
+ decl.hidden_type.ty,
+ decl.hidden_type.span,
+ );
+ Ok(())
+ },
+ "opaque_type_map",
+ ),
+ );
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() {
let reported = infcx.tcx.sess.delay_span_bug(
decl.hidden_type.span,
- &format!("could not resolve {:#?}", hidden_type.ty.kind()),
+ format!("could not resolve {:#?}", hidden_type.ty.kind()),
);
hidden_type.ty = infcx.tcx.ty_error(reported);
}
@@ -274,7 +277,7 @@ fn translate_outlives_facts(typeck: &mut TypeChecker<'_, '_>) {
}
#[track_caller]
-fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: &str) {
+fn mirbug(tcx: TyCtxt<'_>, span: Span, msg: String) {
// We sometimes see MIR failures (notably predicate failures) due to
// the fact that we check rvalue sized predicates here. So use `delay_span_bug`
// to avoid reporting bugs in those cases.
@@ -294,7 +297,6 @@ struct TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
last_span: Span,
- errors_reported: bool,
}
impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
@@ -383,18 +385,16 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
};
};
- if !self.errors_reported {
- let promoted_body = &self.promoted[promoted];
- self.sanitize_promoted(promoted_body, location);
+ let promoted_body = &self.promoted[promoted];
+ self.sanitize_promoted(promoted_body, location);
- let promoted_ty = promoted_body.return_ty();
- check_err(self, promoted_body, ty, promoted_ty);
- }
+ let promoted_ty = promoted_body.return_ty();
+ check_err(self, promoted_body, ty, promoted_ty);
} else {
self.cx.ascribe_user_type(
constant.literal.ty(),
UserType::TypeOf(
- uv.def.did,
+ uv.def,
UserSubsts { substs: uv.substs, user_self_ty: None },
),
locations.span(&self.cx.body),
@@ -483,9 +483,6 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> {
for local_decl in &body.local_decls {
self.sanitize_type(local_decl, local_decl.ty);
}
- if self.errors_reported {
- return;
- }
self.super_body(body);
}
}
@@ -495,7 +492,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
cx: &'a mut TypeChecker<'b, 'tcx>,
promoted: &'b IndexSlice<Promoted, Body<'tcx>>,
) -> Self {
- TypeVerifier { promoted, last_span: cx.body.span, cx, errors_reported: false }
+ TypeVerifier { promoted, last_span: cx.body.span, cx }
}
fn body(&self) -> &Body<'tcx> {
@@ -529,7 +526,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
for elem in place.projection.iter() {
if place_ty.variant_index.is_none() {
if let Err(guar) = place_ty.ty.error_reported() {
- assert!(self.errors_reported);
return PlaceTy::from_ty(self.tcx().ty_error(guar));
}
}
@@ -538,7 +534,8 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
if let PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy) = context {
let tcx = self.tcx();
- let trait_ref = tcx.at(self.last_span).mk_trait_ref(LangItem::Copy, [place_ty.ty]);
+ let trait_ref =
+ ty::TraitRef::from_lang_item(tcx, LangItem::Copy, self.last_span, [place_ty.ty]);
// To have a `Copy` operand, the type `T` of the
// value must be `Copy`. Note that we prove that `T: Copy`,
@@ -592,10 +589,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
self.visit_body(&promoted_body);
- if !self.errors_reported {
- // if verifier failed, don't do further checks to avoid ICEs
- self.cx.typeck_mir(promoted_body);
- }
+ self.cx.typeck_mir(promoted_body);
self.cx.body = parent_body;
// Merge the outlives constraints back in, at the given location.
@@ -761,7 +755,6 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
}
fn error(&mut self) -> Ty<'tcx> {
- self.errors_reported = true;
self.tcx().ty_error_misc()
}
@@ -771,15 +764,12 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> {
match context {
PlaceContext::MutatingUse(_) => ty::Invariant,
- PlaceContext::NonUse(StorageDead | StorageLive | PlaceMention | VarDebugInfo) => {
- ty::Invariant
- }
+ PlaceContext::NonUse(StorageDead | StorageLive | VarDebugInfo) => ty::Invariant,
PlaceContext::NonMutatingUse(
- Inspect | Copy | Move | SharedBorrow | ShallowBorrow | AddressOf | Projection
- ) => {
- ty::Covariant
- },
- PlaceContext::NonUse(AscribeUserTy) => ty::Covariant,
+ Inspect | Copy | Move | PlaceMention | SharedBorrow | ShallowBorrow | AddressOf
+ | Projection,
+ ) => ty::Covariant,
+ PlaceContext::NonUse(AscribeUserTy(variance)) => variance,
}
}
@@ -1043,6 +1033,57 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
checker
}
+ pub(super) fn register_predefined_opaques_in_new_solver(&mut self) {
+ // OK to use the identity substitutions for each opaque type key, since
+ // we remap opaques from HIR typeck back to their definition params.
+ let opaques: Vec<_> = self
+ .infcx
+ .tcx
+ .typeck(self.body.source.def_id().expect_local())
+ .concrete_opaque_types
+ .iter()
+ .map(|(&def_id, &hidden_ty)| {
+ let substs = ty::InternalSubsts::identity_for_item(self.infcx.tcx, def_id);
+ (ty::OpaqueTypeKey { def_id, substs }, hidden_ty)
+ })
+ .collect();
+
+ let renumbered_opaques = self.infcx.tcx.fold_regions(opaques, |_, _| {
+ self.infcx.next_nll_region_var(
+ NllRegionVariableOrigin::Existential { from_forall: false },
+ || RegionCtxt::Unknown,
+ )
+ });
+
+ let param_env = self.param_env;
+ let result = self.fully_perform_op(
+ Locations::All(self.body.span),
+ ConstraintCategory::OpaqueType,
+ CustomTypeOp::new(
+ |ocx| {
+ for (key, hidden_ty) in renumbered_opaques {
+ ocx.register_infer_ok_obligations(
+ ocx.infcx.register_hidden_type_in_new_solver(
+ key,
+ param_env,
+ hidden_ty.ty,
+ )?,
+ );
+ }
+ Ok(())
+ },
+ "register pre-defined opaques",
+ ),
+ );
+
+ if result.is_err() {
+ self.infcx.tcx.sess.delay_span_bug(
+ self.body.span,
+ "failed re-defining predefined opaques in mir typeck",
+ );
+ }
+ }
+
fn body(&self) -> &Body<'tcx> {
self.body
}
@@ -1093,7 +1134,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
sup: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
- ) -> Fallible<()> {
+ ) -> Result<(), NoSolution> {
// Use this order of parameters because the sup type is usually the
// "expected" type in diagnostics.
self.relate_types(sup, ty::Variance::Contravariant, sub, locations, category)
@@ -1106,7 +1147,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
found: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
- ) -> Fallible<()> {
+ ) -> Result<(), NoSolution> {
self.relate_types(expected, ty::Variance::Invariant, found, locations, category)
}
@@ -1118,7 +1159,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
user_ty: &UserTypeProjection,
locations: Locations,
category: ConstraintCategory<'tcx>,
- ) -> Fallible<()> {
+ ) -> Result<(), NoSolution> {
let annotated_type = self.user_type_annotations[user_ty.base].inferred_ty;
trace!(?annotated_type);
let mut curr_projected_ty = PlaceTy::from_ty(annotated_type);
@@ -1238,8 +1279,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.check_rvalue(body, rv, location);
if !self.unsized_feature_enabled() {
- let trait_ref =
- tcx.at(self.last_span).mk_trait_ref(LangItem::Sized, [place_ty]);
+ let trait_ref = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ self.last_span,
+ [place_ty],
+ );
self.prove_trait_ref(
trait_ref,
location.to_locations(),
@@ -1405,7 +1450,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
span_mirbug!(self, term, "bad Assert ({:?}, not bool", cond_ty);
}
- if let AssertKind::BoundsCheck { len, index } = msg {
+ if let AssertKind::BoundsCheck { len, index } = &**msg {
if len.ty(body, tcx) != tcx.types.usize {
span_mirbug!(self, len, "bounds-check length non-usize {:?}", len)
}
@@ -1767,7 +1812,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
let tcx = self.tcx();
- let def_id = uv.def.def_id_for_type_of();
+ let def_id = uv.def;
if tcx.def_kind(def_id) == DefKind::InlineConst {
let def_id = def_id.expect_local();
let predicates =
@@ -1799,6 +1844,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::Repeat(operand, len) => {
self.check_operand(operand, location);
+ let array_ty = rvalue.ty(body.local_decls(), tcx);
+ self.prove_predicate(
+ ty::PredicateKind::WellFormed(array_ty.into()),
+ Locations::Single(location),
+ ConstraintCategory::Boring,
+ );
+
// If the length cannot be evaluated we must assume that the length can be larger
// than 1.
// If the length is larger than 1, the repeat expression will need to copy the
@@ -1811,7 +1863,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Operand::Move(place) => {
// Make sure that repeated elements implement `Copy`.
let ty = place.ty(body, tcx).ty;
- let trait_ref = tcx.at(span).mk_trait_ref(LangItem::Copy, [ty]);
+ let trait_ref =
+ ty::TraitRef::from_lang_item(tcx, LangItem::Copy, span, [ty]);
self.prove_trait_ref(
trait_ref,
@@ -1824,7 +1877,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
}
&Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, ty) => {
- let trait_ref = tcx.at(span).mk_trait_ref(LangItem::Sized, [ty]);
+ let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [ty]);
self.prove_trait_ref(
trait_ref,
@@ -1836,7 +1889,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::ShallowInitBox(operand, ty) => {
self.check_operand(operand, location);
- let trait_ref = tcx.at(span).mk_trait_ref(LangItem::Sized, [*ty]);
+ let trait_ref = ty::TraitRef::from_lang_item(tcx, LangItem::Sized, span, [*ty]);
self.prove_trait_ref(
trait_ref,
@@ -1933,9 +1986,12 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
CastKind::Pointer(PointerCast::Unsize) => {
let &ty = ty;
- let trait_ref = tcx
- .at(span)
- .mk_trait_ref(LangItem::CoerceUnsized, [op.ty(body, tcx), ty]);
+ let trait_ref = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::CoerceUnsized,
+ span,
+ [op.ty(body, tcx), ty],
+ );
self.prove_trait_ref(
trait_ref,
@@ -2307,7 +2363,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
Rvalue::AddressOf(..)
| Rvalue::ThreadLocalRef(..)
| Rvalue::Len(..)
- | Rvalue::Discriminant(..) => {}
+ | Rvalue::Discriminant(..)
+ | Rvalue::NullaryOp(NullOp::OffsetOf(..), _) => {}
}
}
@@ -2698,10 +2755,20 @@ impl<'tcx> TypeOp<'tcx> for InstantiateOpaqueType<'tcx> {
/// constraints in our `InferCtxt`
type ErrorInfo = InstantiateOpaqueType<'tcx>;
- fn fully_perform(mut self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
- let (mut output, region_constraints) = scrape_region_constraints(infcx, || {
- Ok(InferOk { value: (), obligations: self.obligations.clone() })
- })?;
+ fn fully_perform(
+ mut self,
+ infcx: &InferCtxt<'tcx>,
+ span: Span,
+ ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
+ let (mut output, region_constraints) = scrape_region_constraints(
+ infcx,
+ |ocx| {
+ ocx.register_obligations(self.obligations.clone());
+ Ok(())
+ },
+ "InstantiateOpaqueType",
+ span,
+ )?;
self.region_constraints = Some(region_constraints);
output.error_info = Some(self);
Ok(output)
diff --git a/compiler/rustc_borrowck/src/type_check/relate_tys.rs b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
index 7e6d17ec3..8c4bfb2c6 100644
--- a/compiler/rustc_borrowck/src/type_check/relate_tys.rs
+++ b/compiler/rustc_borrowck/src/type_check/relate_tys.rs
@@ -1,12 +1,13 @@
+use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_infer::traits::PredicateObligations;
use rustc_middle::mir::ConstraintCategory;
+use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{self, Ty};
use rustc_span::symbol::sym;
use rustc_span::{Span, Symbol};
-use rustc_trait_selection::traits::query::Fallible;
use crate::constraints::OutlivesConstraint;
use crate::diagnostics::UniverseInfo;
@@ -30,7 +31,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
b: Ty<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
- ) -> Fallible<()> {
+ ) -> Result<(), NoSolution> {
TypeRelating::new(
self.infcx,
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::relate(a, b)),
@@ -47,7 +48,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
b: ty::SubstsRef<'tcx>,
locations: Locations,
category: ConstraintCategory<'tcx>,
- ) -> Fallible<()> {
+ ) -> Result<(), NoSolution> {
TypeRelating::new(
self.infcx,
NllTypeRelatingDelegate::new(self, locations, category, UniverseInfo::other()),
@@ -131,9 +132,13 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
ty::BoundRegionKind::BrEnv => BoundRegionInfo::Name(sym::env),
};
- if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
+ if cfg!(debug_assertions) {
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
- var_to_origin.insert(reg.as_var(), RegionCtxt::Placeholder(reg_info));
+ let new = RegionCtxt::Placeholder(reg_info);
+ let prev = var_to_origin.insert(reg.as_var(), new);
+ if let Some(prev) = prev {
+ assert_eq!(new, prev);
+ }
}
reg
@@ -146,9 +151,10 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
universe,
);
- if cfg!(debug_assertions) && !self.type_checker.infcx.inside_canonicalization_ctxt() {
+ if cfg!(debug_assertions) {
let mut var_to_origin = self.type_checker.infcx.reg_var_to_origin.borrow_mut();
- var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
+ let prev = var_to_origin.insert(reg.as_var(), RegionCtxt::Existential(None));
+ assert_eq!(prev, None);
}
reg
@@ -180,17 +186,15 @@ impl<'tcx> TypeRelatingDelegate<'tcx> for NllTypeRelatingDelegate<'_, '_, 'tcx>
}
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
- self.type_checker
- .fully_perform_op(
- self.locations,
- self.category,
- InstantiateOpaqueType {
- obligations,
- // These fields are filled in during execution of the operation
- base_universe: None,
- region_constraints: None,
- },
- )
- .unwrap();
+ let _: Result<_, ErrorGuaranteed> = self.type_checker.fully_perform_op(
+ self.locations,
+ self.category,
+ InstantiateOpaqueType {
+ obligations,
+ // These fields are filled in during execution of the operation
+ base_universe: None,
+ region_constraints: None,
+ },
+ );
}
}
diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs
index 70fddb105..56f078f2d 100644
--- a/compiler/rustc_borrowck/src/universal_regions.rs
+++ b/compiler/rustc_borrowck/src/universal_regions.rs
@@ -19,7 +19,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
use rustc_hir::BodyOwnerKind;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::IndexVec;
use rustc_infer::infer::NllRegionVariableOrigin;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, InlineConstSubsts, InlineConstSubstsParts, RegionVid, Ty, TyCtxt};
@@ -226,7 +226,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// known between those regions.
pub fn new(
infcx: &BorrowckInferCtxt<'_, 'tcx>,
- mir_def: ty::WithOptConstParam<LocalDefId>,
+ mir_def: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
UniversalRegionsBuilder { infcx, mir_def, param_env }.build()
@@ -289,7 +289,7 @@ impl<'tcx> UniversalRegions<'tcx> {
/// Returns an iterator over all the RegionVids corresponding to
/// universally quantified free regions.
pub fn universal_regions(&self) -> impl Iterator<Item = RegionVid> {
- (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::new)
+ (FIRST_GLOBAL_INDEX..self.num_universals).map(RegionVid::from_usize)
}
/// Returns `true` if `r` is classified as an local region.
@@ -335,7 +335,7 @@ impl<'tcx> UniversalRegions<'tcx> {
pub(crate) fn annotate(&self, tcx: TyCtxt<'tcx>, err: &mut Diagnostic) {
match self.defining_ty {
DefiningTy::Closure(def_id, substs) => {
- err.note(&format!(
+ err.note(format!(
"defining type: {} with closure substs {:#?}",
tcx.def_path_str_with_substs(def_id, substs),
&substs[tcx.generics_of(def_id).parent_count..],
@@ -347,11 +347,11 @@ impl<'tcx> UniversalRegions<'tcx> {
// and other things that are not stable across tests!
// So we just include the region-vid. Annoying.
for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
- err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
+ err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
});
}
DefiningTy::Generator(def_id, substs, _) => {
- err.note(&format!(
+ err.note(format!(
"defining type: {} with generator substs {:#?}",
tcx.def_path_str_with_substs(def_id, substs),
&substs[tcx.generics_of(def_id).parent_count..],
@@ -361,23 +361,23 @@ impl<'tcx> UniversalRegions<'tcx> {
// `r` but doing so is not stable across architectures
// and so forth.
for_each_late_bound_region_in_recursive_scope(tcx, def_id.expect_local(), |r| {
- err.note(&format!("late-bound region is {:?}", self.to_region_vid(r)));
+ err.note(format!("late-bound region is {:?}", self.to_region_vid(r)));
});
}
DefiningTy::FnDef(def_id, substs) => {
- err.note(&format!(
+ err.note(format!(
"defining type: {}",
tcx.def_path_str_with_substs(def_id, substs),
));
}
DefiningTy::Const(def_id, substs) => {
- err.note(&format!(
+ err.note(format!(
"defining constant type: {}",
tcx.def_path_str_with_substs(def_id, substs),
));
}
DefiningTy::InlineConst(def_id, substs) => {
- err.note(&format!(
+ err.note(format!(
"defining inline constant type: {}",
tcx.def_path_str_with_substs(def_id, substs),
));
@@ -388,7 +388,7 @@ impl<'tcx> UniversalRegions<'tcx> {
struct UniversalRegionsBuilder<'cx, 'tcx> {
infcx: &'cx BorrowckInferCtxt<'cx, 'tcx>,
- mir_def: ty::WithOptConstParam<LocalDefId>,
+ mir_def: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
}
@@ -417,12 +417,12 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let mut indices = self.compute_indices(fr_static, defining_ty);
debug!("build: indices={:?}", indices);
- let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = self.infcx.tcx.typeck_root_def_id(self.mir_def.to_def_id());
// If this is a 'root' body (not a closure/generator/inline const), then
// there are no extern regions, so the local regions start at the same
// position as the (empty) sub-list of extern regions
- let first_local_index = if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ let first_local_index = if self.mir_def.to_def_id() == typeck_root_def_id {
first_extern_index
} else {
// If this is a closure, generator, or inline-const, then the late-bound regions from the enclosing
@@ -433,7 +433,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// }
for_each_late_bound_region_in_recursive_scope(
self.infcx.tcx,
- self.infcx.tcx.local_parent(self.mir_def.did),
+ self.infcx.tcx.local_parent(self.mir_def),
|r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
@@ -462,13 +462,13 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let inputs_and_output = self.infcx.replace_bound_regions_with_nll_infer_vars(
FR,
- self.mir_def.did,
+ self.mir_def,
bound_inputs_and_output,
&mut indices,
);
// Converse of above, if this is a function/closure then the late-bound regions declared on its
// signature are local.
- for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def.did, |r| {
+ for_each_late_bound_region_in_item(self.infcx.tcx, self.mir_def, |r| {
debug!(?r);
if !indices.indices.contains_key(&r) {
let region_vid = {
@@ -492,7 +492,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
if self.infcx.tcx.fn_sig(def_id).skip_binder().c_variadic() {
let va_list_did = self.infcx.tcx.require_lang_item(
LangItem::VaList,
- Some(self.infcx.tcx.def_span(self.mir_def.did)),
+ Some(self.infcx.tcx.def_span(self.mir_def)),
);
let reg_vid = self
@@ -544,11 +544,11 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
/// see `DefiningTy` for details.
fn defining_ty(&self) -> DefiningTy<'tcx> {
let tcx = self.infcx.tcx;
- let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
- match tcx.hir().body_owner_kind(self.mir_def.did) {
+ match tcx.hir().body_owner_kind(self.mir_def) {
BodyOwnerKind::Closure | BodyOwnerKind::Fn => {
- let defining_ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
+ let defining_ty = tcx.type_of(self.mir_def).subst_identity();
debug!("defining_ty (pre-replacement): {:?}", defining_ty);
@@ -562,9 +562,9 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
}
ty::FnDef(def_id, substs) => DefiningTy::FnDef(def_id, substs),
_ => span_bug!(
- tcx.def_span(self.mir_def.did),
+ tcx.def_span(self.mir_def),
"expected defining type for `{:?}`: `{:?}`",
- self.mir_def.did,
+ self.mir_def,
defining_ty
),
}
@@ -572,10 +572,10 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
BodyOwnerKind::Const | BodyOwnerKind::Static(..) => {
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
- if self.mir_def.did.to_def_id() == typeck_root_def_id {
+ if self.mir_def.to_def_id() == typeck_root_def_id {
let substs =
self.infcx.replace_free_regions_with_nll_infer_vars(FR, identity_substs);
- DefiningTy::Const(self.mir_def.did.to_def_id(), substs)
+ DefiningTy::Const(self.mir_def.to_def_id(), substs)
} else {
// FIXME this line creates a dependency between borrowck and typeck.
//
@@ -587,15 +587,15 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
// below), so that `type_of(inline_const_def_id).substs(substs)` uses the
// proper type with NLL infer vars.
let ty = tcx
- .typeck(self.mir_def.did)
- .node_type(tcx.local_def_id_to_hir_id(self.mir_def.did));
+ .typeck(self.mir_def)
+ .node_type(tcx.local_def_id_to_hir_id(self.mir_def));
let substs = InlineConstSubsts::new(
tcx,
InlineConstSubstsParts { parent_substs: identity_substs, ty },
)
.substs;
let substs = self.infcx.replace_free_regions_with_nll_infer_vars(FR, substs);
- DefiningTy::InlineConst(self.mir_def.did.to_def_id(), substs)
+ DefiningTy::InlineConst(self.mir_def.to_def_id(), substs)
}
}
}
@@ -611,7 +611,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
defining_ty: DefiningTy<'tcx>,
) -> UniversalRegionIndices<'tcx> {
let tcx = self.infcx.tcx;
- let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.did.to_def_id());
+ let typeck_root_def_id = tcx.typeck_root_def_id(self.mir_def.to_def_id());
let identity_substs = InternalSubsts::identity_for_item(tcx, typeck_root_def_id);
let fr_substs = match defining_ty {
DefiningTy::Closure(_, substs)
@@ -647,7 +647,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
let tcx = self.infcx.tcx;
match defining_ty {
DefiningTy::Closure(def_id, substs) => {
- assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ assert_eq!(self.mir_def.to_def_id(), def_id);
let closure_sig = substs.as_closure().sig();
let inputs_and_output = closure_sig.inputs_and_output();
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
@@ -682,7 +682,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
}
DefiningTy::Generator(def_id, substs, movability) => {
- assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ assert_eq!(self.mir_def.to_def_id(), def_id);
let resume_ty = substs.as_generator().resume_ty();
let output = substs.as_generator().return_ty();
let generator_ty = tcx.mk_generator(def_id, substs, movability);
@@ -700,14 +700,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
DefiningTy::Const(def_id, _) => {
// For a constant body, there are no inputs, and one
// "output" (the type of the constant).
- assert_eq!(self.mir_def.did.to_def_id(), def_id);
- let ty = tcx.type_of(self.mir_def.def_id_for_type_of()).subst_identity();
+ assert_eq!(self.mir_def.to_def_id(), def_id);
+ let ty = tcx.type_of(self.mir_def).subst_identity();
let ty = indices.fold_to_region_vids(tcx, ty);
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
DefiningTy::InlineConst(def_id, substs) => {
- assert_eq!(self.mir_def.did.to_def_id(), def_id);
+ assert_eq!(self.mir_def.to_def_id(), def_id);
let ty = substs.as_inline_const().ty();
ty::Binder::dummy(tcx.mk_type_list(&[ty]))
}
diff --git a/compiler/rustc_const_eval/src/util/collect_writes.rs b/compiler/rustc_borrowck/src/util/collect_writes.rs
index 8d92bb359..8d92bb359 100644
--- a/compiler/rustc_const_eval/src/util/collect_writes.rs
+++ b/compiler/rustc_borrowck/src/util/collect_writes.rs
diff --git a/compiler/rustc_borrowck/src/util/mod.rs b/compiler/rustc_borrowck/src/util/mod.rs
new file mode 100644
index 000000000..7377d4de7
--- /dev/null
+++ b/compiler/rustc_borrowck/src/util/mod.rs
@@ -0,0 +1,3 @@
+mod collect_writes;
+
+pub use collect_writes::FindAssignments;
diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml
index 336e14ef9..44012e802 100644
--- a/compiler/rustc_builtin_macros/Cargo.toml
+++ b/compiler/rustc_builtin_macros/Cargo.toml
@@ -14,9 +14,11 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
+rustc_index = { path = "../rustc_index" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_parse_format = { path = "../rustc_parse_format" }
rustc_parse = { path = "../rustc_parse" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_builtin_macros/messages.ftl b/compiler/rustc_builtin_macros/messages.ftl
index 83dc1ac50..f00cd39cb 100644
--- a/compiler/rustc_builtin_macros/messages.ftl
+++ b/compiler/rustc_builtin_macros/messages.ftl
@@ -1,10 +1,50 @@
-builtin_macros_requires_cfg_pattern =
- macro requires a cfg-pattern as an argument
- .label = cfg-pattern required
+builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
-builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
+builtin_macros_asm_clobber_abi = clobber_abi
+builtin_macros_asm_clobber_no_reg = asm with `clobber_abi` must specify explicit registers for outputs
+builtin_macros_asm_clobber_outputs = generic outputs
-builtin_macros_alloc_error_must_be_fn = alloc_error_handler must be a function
+builtin_macros_asm_duplicate_arg = duplicate argument named `{$name}`
+ .label = previously here
+ .arg = duplicate argument
+
+builtin_macros_asm_expected_comma = expected token: `,`
+ .label = expected `,`
+
+builtin_macros_asm_expected_other = expected operand, {$is_global_asm ->
+ [true] options
+ *[false] clobber_abi, options
+ }, or additional template string
+
+builtin_macros_asm_explicit_register_name = explicit register arguments cannot have names
+
+builtin_macros_asm_modifier_invalid = asm template modifier must be a single character
+
+builtin_macros_asm_mutually_exclusive = the `{$opt1}` and `{$opt2}` options are mutually exclusive
+
+builtin_macros_asm_noreturn = asm outputs are not allowed with the `noreturn` option
+
+builtin_macros_asm_opt_already_provided = the `{$symbol}` option was already provided
+ .label = this option was already provided
+ .suggestion = remove this option
+
+builtin_macros_asm_pos_after = positional arguments cannot follow named arguments or explicit register arguments
+ .pos = positional argument
+ .named = named argument
+ .explicit = explicit register argument
+
+builtin_macros_asm_pure_combine = the `pure` option must be combined with either `nomem` or `readonly`
+
+builtin_macros_asm_pure_no_output = asm with the `pure` option must have at least one output
+
+builtin_macros_asm_requires_template = requires at least a template string argument
+
+builtin_macros_asm_sym_no_path = expected a path for argument to `sym`
+
+builtin_macros_asm_underscore_input = _ cannot be used for input operands
+
+builtin_macros_assert_missing_comma = unexpected string literal
+ .suggestion = try adding a comma
builtin_macros_assert_requires_boolean = macro requires a boolean expression as an argument
.label = boolean expression required
@@ -12,51 +52,50 @@ builtin_macros_assert_requires_boolean = macro requires a boolean expression as
builtin_macros_assert_requires_expression = macro requires an expression as an argument
.suggestion = try removing semicolon
-builtin_macros_assert_missing_comma = unexpected string literal
- .suggestion = try adding a comma
+builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
+ .label = not applicable here
+ .label2 = not a `struct`, `enum` or `union`
+
+builtin_macros_cannot_derive_union = this trait cannot be derived for unions
-builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
-builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
-builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
builtin_macros_cfg_accessible_has_args = `cfg_accessible` path cannot accept arguments
builtin_macros_cfg_accessible_indeterminate = cannot determine whether the path is accessible or not
-builtin_macros_concat_bytestr = cannot concatenate a byte string literal
-
-builtin_macros_concat_missing_literal = expected a literal
- .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
+builtin_macros_cfg_accessible_literal_path = `cfg_accessible` path cannot be a literal
+builtin_macros_cfg_accessible_multiple_paths = multiple `cfg_accessible` paths are specified
+builtin_macros_cfg_accessible_unspecified_path = `cfg_accessible` path is not specified
+builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
+ .note = byte strings are treated as arrays of bytes
+ .help = try flattening the array
-builtin_macros_concat_bytes_missing_literal = expected a byte literal
- .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
+builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
builtin_macros_concat_bytes_invalid = cannot concatenate {$lit_kind} literals
.byte_char = try using a byte character
.byte_str = try using a byte string
.number_array = try wrapping the number in an array
-builtin_macros_concat_bytes_oob = numeric literal is out of bounds
+builtin_macros_concat_bytes_missing_literal = expected a byte literal
+ .note = only byte literals (like `b"foo"`, `b's'` and `[3, 4, 5]`) can be passed to `concat_bytes!()`
builtin_macros_concat_bytes_non_u8 = numeric literal is not a `u8`
-builtin_macros_concat_bytes_array = cannot concatenate doubly nested array
- .note = byte strings are treated as arrays of bytes
- .help = try flattening the array
+builtin_macros_concat_bytes_oob = numeric literal is out of bounds
-builtin_macros_concat_bytes_bad_repeat = repeat count is not a positive number
+builtin_macros_concat_bytestr = cannot concatenate a byte string literal
+
+builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
builtin_macros_concat_idents_missing_args = `concat_idents!()` takes 1 or more arguments
builtin_macros_concat_idents_missing_comma = `concat_idents!()` expecting comma
-builtin_macros_concat_idents_ident_args = `concat_idents!()` requires ident args
+builtin_macros_concat_missing_literal = expected a literal
+ .note = only literals (like `"foo"`, `-42` and `3.14`) can be passed to `concat!()`
-builtin_macros_bad_derive_target = `derive` may only be applied to `struct`s, `enum`s and `union`s
- .label = not applicable here
- .label2 = not a `struct`, `enum` or `union`
+builtin_macros_default_arg = `#[default]` attribute does not accept a value
+ .suggestion = try using `#[default]`
-builtin_macros_unexpected_lit = expected path to a trait, found literal
- .label = not a trait
- .str_lit = try using `#[derive({$sym})]`
- .other = for example, write `#[derive(Debug)]` for `Debug`
+builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept arguments
.suggestion = remove the arguments
@@ -64,66 +103,38 @@ builtin_macros_derive_path_args_list = traits in `#[derive(...)]` don't accept a
builtin_macros_derive_path_args_value = traits in `#[derive(...)]` don't accept values
.suggestion = remove the value
-builtin_macros_derive_macro_call = `derive` cannot be used on items with type macros
-
-builtin_macros_cannot_derive_union = this trait cannot be derived for unions
-
-builtin_macros_no_default_variant = no default declared
- .help = make a unit variant default by placing `#[default]` above it
- .suggestion = make `{$ident}` default
-
-builtin_macros_multiple_defaults = multiple declared defaults
- .label = first default
- .additional = additional default
- .note = only one variant can be default
- .suggestion = make `{$ident}` default
-
-builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
- .help = consider a manual implementation of `Default`
-
-builtin_macros_non_exhaustive_default = default variant must be exhaustive
- .label = declared `#[non_exhaustive]` here
- .help = consider a manual implementation of `Default`
-
-builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
- .note = only one `#[default]` attribute is needed
- .label = `#[default]` used here
- .label_again = `#[default]` used again here
- .help = try removing {$only_one ->
- [true] this
- *[false] these
- }
-
-builtin_macros_default_arg = `#[default]` attribute does not accept a value
- .suggestion = try using `#[default]`
-
-builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
-
builtin_macros_env_not_defined = environment variable `{$var}` not defined at compile time
.cargo = Cargo sets build script variables at run time. Use `std::env::var("{$var}")` instead
.other = use `std::env::var("{$var}")` to read the variable at run time
-builtin_macros_format_requires_string = requires at least a format string argument
+builtin_macros_env_takes_args = `env!()` takes 1 or 2 arguments
+
+builtin_macros_expected_one_cfg_pattern = expected 1 cfg-pattern
builtin_macros_format_duplicate_arg = duplicate argument named `{$ident}`
.label1 = previously here
.label2 = duplicate argument
+builtin_macros_format_no_arg_named = there is no argument named `{$name}`
+ .note = did you intend to capture a variable `{$name}` from the surrounding scope?
+ .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
+
+builtin_macros_format_pos_mismatch = {$n} positional {$n ->
+ [one] argument
+ *[more] arguments
+ } in format string, but {$desc}
+
builtin_macros_format_positional_after_named = positional arguments cannot follow named arguments
.label = positional arguments must be before named arguments
.named_args = named argument
+builtin_macros_format_requires_string = requires at least a format string argument
+
builtin_macros_format_string_invalid = invalid format string: {$desc}
.label = {$label1} in format string
.note = {$note}
.second_label = {$label}
-builtin_macros_sugg = consider using a positional formatting argument instead
-
-builtin_macros_format_no_arg_named = there is no argument named `{$name}`
- .note = did you intend to capture a variable `{$name}` from the surrounding scope?
- .note2 = to avoid ambiguity, `format_args!` cannot capture variables when the format string is expanded from a macro
-
builtin_macros_format_unknown_trait = unknown format trait `{$ty}`
.note = the only appropriate formatting traits are:
- ``, which uses the `Display` trait
@@ -145,7 +156,49 @@ builtin_macros_format_unused_arg = {$named ->
builtin_macros_format_unused_args = multiple unused formatting arguments
.label = multiple missing formatting specifiers
-builtin_macros_format_pos_mismatch = {$n} positional {$n ->
- [one] argument
- *[more] arguments
- } in format string, but {$desc}
+builtin_macros_global_asm_clobber_abi = `clobber_abi` cannot be used with `global_asm!`
+
+builtin_macros_multiple_default_attrs = multiple `#[default]` attributes
+ .note = only one `#[default]` attribute is needed
+ .label = `#[default]` used here
+ .label_again = `#[default]` used again here
+ .help = try removing {$only_one ->
+ [true] this
+ *[false] these
+ }
+
+builtin_macros_multiple_defaults = multiple declared defaults
+ .label = first default
+ .additional = additional default
+ .note = only one variant can be default
+ .suggestion = make `{$ident}` default
+
+builtin_macros_no_default_variant = no default declared
+ .help = make a unit variant default by placing `#[default]` above it
+ .suggestion = make `{$ident}` default
+
+builtin_macros_non_exhaustive_default = default variant must be exhaustive
+ .label = declared `#[non_exhaustive]` here
+ .help = consider a manual implementation of `Default`
+
+builtin_macros_non_unit_default = the `#[default]` attribute may only be used on unit enum variants
+ .help = consider a manual implementation of `Default`
+
+builtin_macros_requires_cfg_pattern =
+ macro requires a cfg-pattern as an argument
+ .label = cfg-pattern required
+
+builtin_macros_sugg = consider using a positional formatting argument instead
+
+builtin_macros_test_bad_fn = {$kind} functions cannot be used for tests
+ .label = `{$kind}` because of this
+
+builtin_macros_test_case_non_item = `#[test_case]` attribute is only allowed on items
+
+builtin_macros_test_runner_invalid = `test_runner` argument must be a path
+builtin_macros_test_runner_nargs = `#![test_runner(..)]` accepts exactly 1 argument
+
+builtin_macros_unexpected_lit = expected path to a trait, found literal
+ .label = not a trait
+ .str_lit = try using `#[derive({$sym})]`
+ .other = for example, write `#[derive(Debug)]` for `Debug`
diff --git a/compiler/rustc_builtin_macros/src/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs
index 8c1579baa..5217e317a 100644
--- a/compiler/rustc_builtin_macros/src/asm.rs
+++ b/compiler/rustc_builtin_macros/src/asm.rs
@@ -2,9 +2,10 @@ use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter};
use rustc_ast::tokenstream::TokenStream;
-use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{Applicability, PResult};
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
+use rustc_errors::PResult;
use rustc_expand::base::{self, *};
+use rustc_index::bit_set::GrowableBitSet;
use rustc_parse::parser::Parser;
use rustc_parse_format as parse;
use rustc_session::lint;
@@ -15,11 +16,13 @@ use rustc_span::{InnerSpan, Span};
use rustc_target::asm::InlineAsmArch;
use smallvec::smallvec;
+use crate::errors;
+
pub struct AsmArgs {
pub templates: Vec<P<ast::Expr>>,
pub operands: Vec<(ast::InlineAsmOperand, Span)>,
- named_args: FxHashMap<Symbol, usize>,
- reg_args: FxHashSet<usize>,
+ named_args: FxIndexMap<Symbol, usize>,
+ reg_args: GrowableBitSet<usize>,
pub clobber_abis: Vec<(Symbol, Span)>,
options: ast::InlineAsmOptions,
pub options_spans: Vec<Span>,
@@ -47,15 +50,15 @@ pub fn parse_asm_args<'a>(
let diag = &sess.span_diagnostic;
if p.token == token::Eof {
- return Err(diag.struct_span_err(sp, "requires at least a template string argument"));
+ return Err(diag.create_err(errors::AsmRequiresTemplate { span: sp }));
}
let first_template = p.parse_expr()?;
let mut args = AsmArgs {
templates: vec![first_template],
operands: vec![],
- named_args: FxHashMap::default(),
- reg_args: FxHashSet::default(),
+ named_args: Default::default(),
+ reg_args: Default::default(),
clobber_abis: Vec::new(),
options: ast::InlineAsmOptions::empty(),
options_spans: vec![],
@@ -66,10 +69,7 @@ pub fn parse_asm_args<'a>(
if !p.eat(&token::Comma) {
if allow_templates {
// After a template string, we always expect *only* a comma...
- let mut err = diag.struct_span_err(p.token.span, "expected token: `,`");
- err.span_label(p.token.span, "expected `,`");
- p.maybe_annotate_with_ascription(&mut err, false);
- return Err(err);
+ return Err(diag.create_err(errors::AsmExpectedComma { span: p.token.span }));
} else {
// ...after that delegate to `expect` to also include the other expected tokens.
return Err(p.expect(&token::Comma).err().unwrap());
@@ -110,7 +110,7 @@ pub fn parse_asm_args<'a>(
let op = if !is_global_asm && p.eat_keyword(kw::In) {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
@@ -126,7 +126,7 @@ pub fn parse_asm_args<'a>(
} else if !is_global_asm && p.eat_keyword(sym::inout) {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
@@ -140,7 +140,7 @@ pub fn parse_asm_args<'a>(
} else if !is_global_asm && p.eat_keyword(sym::inlateout) {
let reg = parse_reg(p, &mut explicit_reg)?;
if p.eat_keyword(kw::Underscore) {
- let err = diag.struct_span_err(p.token.span, "_ cannot be used for input operands");
+ let err = diag.create_err(errors::AsmUnderscoreInput { span: p.token.span });
return Err(err);
}
let expr = p.parse_expr()?;
@@ -158,7 +158,7 @@ pub fn parse_asm_args<'a>(
let expr = p.parse_expr()?;
let ast::ExprKind::Path(qself, path) = &expr.kind else {
let err = diag
- .struct_span_err(expr.span, "expected a path for argument to `sym`");
+ .create_err(errors::AsmSymNoPath { span: expr.span });
return Err(err);
};
let sym = ast::InlineAsmSym {
@@ -179,13 +179,10 @@ pub fn parse_asm_args<'a>(
) => {}
ast::ExprKind::MacCall(..) => {}
_ => {
- let errstr = if is_global_asm {
- "expected operand, options, or additional template string"
- } else {
- "expected operand, clobber_abi, options, or additional template string"
- };
- let mut err = diag.struct_span_err(template.span, errstr);
- err.span_label(template.span, errstr);
+ let err = diag.create_err(errors::AsmExpectedOther {
+ span: template.span,
+ is_global_asm,
+ });
return Err(err);
}
}
@@ -205,33 +202,21 @@ pub fn parse_asm_args<'a>(
// of the argument available.
if explicit_reg {
if name.is_some() {
- diag.struct_span_err(span, "explicit register arguments cannot have names").emit();
+ diag.emit_err(errors::AsmExplicitRegisterName { span });
}
args.reg_args.insert(slot);
} else if let Some(name) = name {
if let Some(&prev) = args.named_args.get(&name) {
- diag.struct_span_err(span, &format!("duplicate argument named `{}`", name))
- .span_label(args.operands[prev].1, "previously here")
- .span_label(span, "duplicate argument")
- .emit();
+ diag.emit_err(errors::AsmDuplicateArg { span, name, prev: args.operands[prev].1 });
continue;
}
args.named_args.insert(name, slot);
} else {
if !args.named_args.is_empty() || !args.reg_args.is_empty() {
- let mut err = diag.struct_span_err(
- span,
- "positional arguments cannot follow named arguments \
- or explicit register arguments",
- );
- err.span_label(span, "positional argument");
- for pos in args.named_args.values() {
- err.span_label(args.operands[*pos].1, "named argument");
- }
- for pos in &args.reg_args {
- err.span_label(args.operands[*pos].1, "explicit register argument");
- }
- err.emit();
+ let named = args.named_args.values().map(|p| args.operands[*p].1).collect();
+ let explicit = args.reg_args.iter().map(|p| args.operands[p].1).collect();
+
+ diag.emit_err(errors::AsmPositionalAfter { span, named, explicit });
}
}
}
@@ -240,25 +225,19 @@ pub fn parse_asm_args<'a>(
&& args.options.contains(ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- diag.struct_span_err(spans, "the `nomem` and `readonly` options are mutually exclusive")
- .emit();
+ diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "nomem", opt2: "readonly" });
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& args.options.contains(ast::InlineAsmOptions::NORETURN)
{
let spans = args.options_spans.clone();
- diag.struct_span_err(spans, "the `pure` and `noreturn` options are mutually exclusive")
- .emit();
+ diag.emit_err(errors::AsmMutuallyExclusive { spans, opt1: "pure", opt2: "noreturn" });
}
if args.options.contains(ast::InlineAsmOptions::PURE)
&& !args.options.intersects(ast::InlineAsmOptions::NOMEM | ast::InlineAsmOptions::READONLY)
{
let spans = args.options_spans.clone();
- diag.struct_span_err(
- spans,
- "the `pure` option must be combined with either `nomem` or `readonly`",
- )
- .emit();
+ diag.emit_err(errors::AsmPureCombine { spans });
}
let mut have_real_output = false;
@@ -285,41 +264,28 @@ pub fn parse_asm_args<'a>(
}
}
if args.options.contains(ast::InlineAsmOptions::PURE) && !have_real_output {
- diag.struct_span_err(
- args.options_spans.clone(),
- "asm with the `pure` option must have at least one output",
- )
- .emit();
+ diag.emit_err(errors::AsmPureNoOutput { spans: args.options_spans.clone() });
}
if args.options.contains(ast::InlineAsmOptions::NORETURN) && !outputs_sp.is_empty() {
- let err = diag
- .struct_span_err(outputs_sp, "asm outputs are not allowed with the `noreturn` option");
-
+ let err = diag.create_err(errors::AsmNoReturn { outputs_sp });
// Bail out now since this is likely to confuse MIR
return Err(err);
}
if args.clobber_abis.len() > 0 {
if is_global_asm {
- let err = diag.struct_span_err(
- args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
- "`clobber_abi` cannot be used with `global_asm!`",
- );
+ let err = diag.create_err(errors::GlobalAsmClobberAbi {
+ spans: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+ });
// Bail out now since this is likely to confuse later stages
return Err(err);
}
if !regclass_outputs.is_empty() {
- diag.struct_span_err(
- regclass_outputs.clone(),
- "asm with `clobber_abi` must specify explicit registers for outputs",
- )
- .span_labels(
- args.clobber_abis.iter().map(|(_, span)| *span).collect::<Vec<Span>>(),
- "clobber_abi",
- )
- .span_labels(regclass_outputs, "generic outputs")
- .emit();
+ diag.emit_err(errors::AsmClobberNoReg {
+ spans: regclass_outputs,
+ clobbers: args.clobber_abis.iter().map(|(_, span)| *span).collect(),
+ });
}
}
@@ -331,25 +297,9 @@ pub fn parse_asm_args<'a>(
/// This function must be called immediately after the option token is parsed.
/// Otherwise, the suggestion will be incorrect.
fn err_duplicate_option(p: &mut Parser<'_>, symbol: Symbol, span: Span) {
- let mut err = p
- .sess
- .span_diagnostic
- .struct_span_err(span, &format!("the `{}` option was already provided", symbol));
- err.span_label(span, "this option was already provided");
-
// Tool-only output
- let mut full_span = span;
- if p.token.kind == token::Comma {
- full_span = full_span.to(p.token.span);
- }
- err.tool_only_span_suggestion(
- full_span,
- "remove this option",
- "",
- Applicability::MachineApplicable,
- );
-
- err.emit();
+ let full_span = if p.token.kind == token::Comma { span.to(p.token.span) } else { span };
+ p.sess.span_diagnostic.emit_err(errors::AsmOptAlreadyprovided { span, symbol, full_span });
}
/// Try to set the provided option in the provided `AsmArgs`.
@@ -497,8 +447,8 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
// Register operands are implicitly used since they are not allowed to be
// referenced in the template string.
let mut used = vec![false; args.operands.len()];
- for pos in &args.reg_args {
- used[*pos] = true;
+ for pos in args.reg_args.iter() {
+ used[pos] = true;
}
let named_pos: FxHashMap<usize, Symbol> =
args.named_args.iter().map(|(&sym, &idx)| (idx, sym)).collect();
@@ -600,11 +550,11 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
if !parser.errors.is_empty() {
let err = parser.errors.remove(0);
let err_sp = template_span.from_inner(InnerSpan::new(err.span.start, err.span.end));
- let msg = &format!("invalid asm template string: {}", err.description);
+ let msg = format!("invalid asm template string: {}", err.description);
let mut e = ecx.struct_span_err(err_sp, msg);
e.span_label(err_sp, err.label + " in asm template string");
if let Some(note) = err.note {
- e.note(&note);
+ e.note(note);
}
if let Some((label, span)) = err.secondary_label {
let err_sp = template_span.from_inner(InnerSpan::new(span.start, span.end));
@@ -632,10 +582,10 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
parse::ArgumentIs(idx) | parse::ArgumentImplicitlyIs(idx) => {
if idx >= args.operands.len()
|| named_pos.contains_key(&idx)
- || args.reg_args.contains(&idx)
+ || args.reg_args.contains(idx)
{
let msg = format!("invalid reference to argument at index {}", idx);
- let mut err = ecx.struct_span_err(span, &msg);
+ let mut err = ecx.struct_span_err(span, msg);
err.span_label(span, "from here");
let positional_args = args.operands.len()
@@ -651,7 +601,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
1 => format!("there is 1 {}argument", positional),
x => format!("there are {} {}arguments", x, positional),
};
- err.note(&msg);
+ err.note(msg);
if named_pos.contains_key(&idx) {
err.span_label(args.operands[idx].1, "named argument");
@@ -659,7 +609,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
args.operands[idx].1,
"named arguments cannot be referenced by position",
);
- } else if args.reg_args.contains(&idx) {
+ } else if args.reg_args.contains(idx) {
err.span_label(
args.operands[idx].1,
"explicit register argument",
@@ -688,7 +638,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
ecx.struct_span_err(
template_span
.from_inner(InnerSpan::new(span.start, span.end)),
- &msg,
+ msg,
)
.emit();
None
@@ -705,11 +655,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
.ty_span
.map(|sp| template_sp.from_inner(InnerSpan::new(sp.start, sp.end)))
.unwrap_or(template_sp);
- ecx.struct_span_err(
- span,
- "asm template modifier must be a single character",
- )
- .emit();
+ ecx.emit_err(errors::AsmModifierInvalid { span });
modifier = None;
}
@@ -758,7 +704,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
let (sp, msg) = unused_operands.into_iter().next().unwrap();
let mut err = ecx.struct_span_err(sp, msg);
err.span_label(sp, msg);
- err.help(&format!(
+ err.help(format!(
"if this argument is intentionally unused, \
consider using it in an asm comment: `\"/*{} */\"`",
help_str
@@ -773,7 +719,7 @@ fn expand_preparsed_asm(ecx: &mut ExtCtxt<'_>, args: AsmArgs) -> Option<ast::Inl
for (sp, msg) in unused_operands {
err.span_label(sp, msg);
}
- err.help(&format!(
+ err.help(format!(
"if these arguments are intentionally unused, \
consider using them in an asm comment: `\"/*{} */\"`",
help_str
diff --git a/compiler/rustc_builtin_macros/src/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs
index 0de424be2..ab4ea9c8c 100644
--- a/compiler/rustc_builtin_macros/src/assert.rs
+++ b/compiler/rustc_builtin_macros/src/assert.rs
@@ -61,7 +61,6 @@ pub fn expand_assert<'cx>(
delim: MacDelimiter::Parenthesis,
tokens,
}),
- prior_type_ascription: None,
})),
);
expr_if_not(cx, call_site_span, cond_expr, then, None)
diff --git a/compiler/rustc_builtin_macros/src/assert/context.rs b/compiler/rustc_builtin_macros/src/assert/context.rs
index c9e3cd486..b619e80e1 100644
--- a/compiler/rustc_builtin_macros/src/assert/context.rs
+++ b/compiler/rustc_builtin_macros/src/assert/context.rs
@@ -182,7 +182,6 @@ impl<'cx, 'a> Context<'cx, 'a> {
delim: MacDelimiter::Parenthesis,
tokens: initial.into_iter().chain(captures).collect::<TokenStream>(),
}),
- prior_type_ascription: None,
})),
)
}
@@ -234,10 +233,19 @@ impl<'cx, 'a> Context<'cx, 'a> {
ExprKind::Cast(local_expr, _) => {
self.manage_cond_expr(local_expr);
}
+ ExprKind::If(local_expr, _, _) => {
+ self.manage_cond_expr(local_expr);
+ }
ExprKind::Index(prefix, suffix) => {
self.manage_cond_expr(prefix);
self.manage_cond_expr(suffix);
}
+ ExprKind::Let(_, local_expr, _) => {
+ self.manage_cond_expr(local_expr);
+ }
+ ExprKind::Match(local_expr, _) => {
+ self.manage_cond_expr(local_expr);
+ }
ExprKind::MethodCall(call) => {
for arg in &mut call.args {
self.manage_cond_expr(arg);
@@ -288,7 +296,7 @@ impl<'cx, 'a> Context<'cx, 'a> {
ExprKind::Assign(_, _, _)
| ExprKind::AssignOp(_, _, _)
| ExprKind::Async(_, _)
- | ExprKind::Await(_)
+ | ExprKind::Await(_, _)
| ExprKind::Block(_, _)
| ExprKind::Break(_, _)
| ExprKind::Closure(_)
@@ -296,16 +304,14 @@ impl<'cx, 'a> Context<'cx, 'a> {
| ExprKind::Continue(_)
| ExprKind::Err
| ExprKind::Field(_, _)
- | ExprKind::FormatArgs(_)
| ExprKind::ForLoop(_, _, _, _)
- | ExprKind::If(_, _, _)
+ | ExprKind::FormatArgs(_)
| ExprKind::IncludedBytes(..)
| ExprKind::InlineAsm(_)
- | ExprKind::Let(_, _, _)
| ExprKind::Lit(_)
| ExprKind::Loop(_, _, _)
| ExprKind::MacCall(_)
- | ExprKind::Match(_, _)
+ | ExprKind::OffsetOf(_, _)
| ExprKind::Path(_, _)
| ExprKind::Ret(_)
| ExprKind::Try(_)
diff --git a/compiler/rustc_builtin_macros/src/cfg_eval.rs b/compiler/rustc_builtin_macros/src/cfg_eval.rs
index 750f1fe12..49401e9ca 100644
--- a/compiler/rustc_builtin_macros/src/cfg_eval.rs
+++ b/compiler/rustc_builtin_macros/src/cfg_eval.rs
@@ -119,7 +119,7 @@ impl<'ast> visit::Visitor<'ast> for CfgFinder {
self.has_cfg_or_cfg_attr = self.has_cfg_or_cfg_attr
|| attr
.ident()
- .map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
+ .is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr);
}
}
@@ -166,7 +166,9 @@ impl CfgEval<'_, '_> {
))
},
Annotatable::Stmt(_) => |parser| {
- Ok(Annotatable::Stmt(P(parser.parse_stmt(ForceCollect::Yes)?.unwrap())))
+ Ok(Annotatable::Stmt(P(parser
+ .parse_stmt_without_recovery(false, ForceCollect::Yes)?
+ .unwrap())))
},
Annotatable::Expr(_) => {
|parser| Ok(Annotatable::Expr(parser.parse_expr_force_collect()?))
diff --git a/compiler/rustc_builtin_macros/src/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs
index b92964d03..50e88ae2e 100644
--- a/compiler/rustc_builtin_macros/src/concat.rs
+++ b/compiler/rustc_builtin_macros/src/concat.rs
@@ -32,6 +32,10 @@ pub fn expand_concat(
Ok(ast::LitKind::Bool(b)) => {
accumulator.push_str(&b.to_string());
}
+ Ok(ast::LitKind::CStr(..)) => {
+ cx.span_err(e.span, "cannot concatenate a C string literal");
+ has_errors = true;
+ }
Ok(ast::LitKind::Byte(..) | ast::LitKind::ByteStr(..)) => {
cx.emit_err(errors::ConcatBytestr { span: e.span });
has_errors = true;
diff --git a/compiler/rustc_builtin_macros/src/concat_bytes.rs b/compiler/rustc_builtin_macros/src/concat_bytes.rs
index ba639c0a9..5ef35af0a 100644
--- a/compiler/rustc_builtin_macros/src/concat_bytes.rs
+++ b/compiler/rustc_builtin_macros/src/concat_bytes.rs
@@ -18,6 +18,11 @@ fn invalid_type_err(
};
let snippet = cx.sess.source_map().span_to_snippet(span).ok();
match ast::LitKind::from_token_lit(token_lit) {
+ Ok(ast::LitKind::CStr(_, _)) => {
+ // FIXME(c_str_literals): should concatenation of C string literals
+ // include the null bytes in the end?
+ cx.span_err(span, "cannot concatenate C string literals");
+ }
Ok(ast::LitKind::Char(_)) => {
let sugg =
snippet.map(|snippet| ConcatBytesInvalidSuggestion::CharLit { span, snippet });
diff --git a/compiler/rustc_builtin_macros/src/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs
index 8c737f043..ee56d45c9 100644
--- a/compiler/rustc_builtin_macros/src/concat_idents.rs
+++ b/compiler/rustc_builtin_macros/src/concat_idents.rs
@@ -19,7 +19,7 @@ pub fn expand_concat_idents<'cx>(
}
let mut res_str = String::new();
- for (i, e) in tts.into_trees().enumerate() {
+ for (i, e) in tts.trees().enumerate() {
if i & 1 == 1 {
match e {
TokenTree::Token(Token { kind: token::Comma, .. }, _) => {}
diff --git a/compiler/rustc_builtin_macros/src/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
index 0481a1189..2c8e6f99c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/bounds.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/bounds.rs
@@ -27,3 +27,26 @@ pub fn expand_deriving_copy(
trait_def.expand(cx, mitem, item, push);
}
+
+pub fn expand_deriving_const_param_ty(
+ cx: &mut ExtCtxt<'_>,
+ span: Span,
+ mitem: &MetaItem,
+ item: &Annotatable,
+ push: &mut dyn FnMut(Annotatable),
+ is_const: bool,
+) {
+ let trait_def = TraitDef {
+ span,
+ path: path_std!(marker::ConstParamTy),
+ skip_path_as_bound: false,
+ needs_copy_as_bound_if_packed: false,
+ additional_bounds: Vec::new(),
+ supports_unions: false,
+ methods: Vec::new(),
+ associated_types: Vec::new(),
+ is_const,
+ };
+
+ trait_def.expand(cx, mitem, item, push);
+}
diff --git a/compiler/rustc_builtin_macros/src/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs
index dfee2d3ce..988356374 100644
--- a/compiler/rustc_builtin_macros/src/deriving/clone.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/clone.rs
@@ -145,7 +145,7 @@ fn cs_clone_simple(
}
_ => cx.span_bug(
trait_span,
- &format!("unexpected substructure in simple `derive({})`", name),
+ format!("unexpected substructure in simple `derive({})`", name),
),
}
}
@@ -179,10 +179,10 @@ fn cs_clone(
vdata = &variant.data;
}
EnumTag(..) | AllFieldlessEnum(..) => {
- cx.span_bug(trait_span, &format!("enum tags in `derive({})`", name,))
+ cx.span_bug(trait_span, format!("enum tags in `derive({})`", name,))
}
StaticEnum(..) | StaticStruct(..) => {
- cx.span_bug(trait_span, &format!("associated function in `derive({})`", name))
+ cx.span_bug(trait_span, format!("associated function in `derive({})`", name))
}
}
@@ -194,7 +194,7 @@ fn cs_clone(
let Some(ident) = field.name else {
cx.span_bug(
trait_span,
- &format!("unnamed field in normal struct in `derive({})`", name,),
+ format!("unnamed field in normal struct in `derive({})`", name,),
);
};
let call = subcall(cx, field);
diff --git a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
index e5a003315..4ba09335c 100644
--- a/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
+++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs
@@ -1038,7 +1038,7 @@ impl<'a> MethodDef<'a> {
/// `&self.x` because that might cause an unaligned ref. So for any trait
/// method that takes a reference, we use a local block to force a copy.
/// This requires that the field impl `Copy`.
- /// ```
+ /// ```rust,ignore (example)
/// # struct A { x: u8, y: u8 }
/// impl PartialEq for A {
/// fn eq(&self, other: &A) -> bool {
@@ -1591,7 +1591,7 @@ impl<'a> TraitDef<'a> {
BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
sp,
ast::CRATE_NODE_ID,
- &format!(
+ format!(
"{} slice in a packed struct that derives a built-in trait",
ty
),
diff --git a/compiler/rustc_builtin_macros/src/edition_panic.rs b/compiler/rustc_builtin_macros/src/edition_panic.rs
index b2a21611d..ef0db23ff 100644
--- a/compiler/rustc_builtin_macros/src/edition_panic.rs
+++ b/compiler/rustc_builtin_macros/src/edition_panic.rs
@@ -63,7 +63,6 @@ fn expand<'cx>(
delim: MacDelimiter::Parenthesis,
tokens: tts,
}),
- prior_type_ascription: None,
})),
),
)
diff --git a/compiler/rustc_builtin_macros/src/env.rs b/compiler/rustc_builtin_macros/src/env.rs
index 58c972738..8f64e3328 100644
--- a/compiler/rustc_builtin_macros/src/env.rs
+++ b/compiler/rustc_builtin_macros/src/env.rs
@@ -63,7 +63,8 @@ pub fn expand_env<'cx>(
Some(exprs) => exprs.into_iter(),
};
- let Some((var, _style)) = expr_to_string(cx, exprs.next().unwrap(), "expected string literal") else {
+ let var_expr = exprs.next().unwrap();
+ let Some((var, _)) = expr_to_string(cx, var_expr.clone(), "expected string literal") else {
return DummyResult::any(sp);
};
@@ -71,7 +72,7 @@ pub fn expand_env<'cx>(
None => None,
Some(second) => match expr_to_string(cx, second, "expected string literal") {
None => return DummyResult::any(sp),
- Some((s, _style)) => Some(s),
+ Some((s, _)) => Some(s),
},
};
@@ -80,10 +81,15 @@ pub fn expand_env<'cx>(
cx.sess.parse_sess.env_depinfo.borrow_mut().insert((var, value));
let e = match value {
None => {
+ // Use the string literal in the code in the diagnostic to avoid confusing diagnostics,
+ // e.g. when the literal contains escape sequences.
+ let ast::ExprKind::Lit(ast::token::Lit { kind: ast::token::LitKind::Str, symbol: original_var, ..}) = &var_expr.kind else {
+ unreachable!("`expr_to_string` ensures this is a string lit")
+ };
cx.emit_err(errors::EnvNotDefined {
span: sp,
msg: custom_msg,
- var,
+ var: *original_var,
help: custom_msg.is_none().then(|| help_for_missing_env_var(var.as_str())),
});
return DummyResult::any(sp);
diff --git a/compiler/rustc_builtin_macros/src/errors.rs b/compiler/rustc_builtin_macros/src/errors.rs
index 630f9b87b..d0d786460 100644
--- a/compiler/rustc_builtin_macros/src/errors.rs
+++ b/compiler/rustc_builtin_macros/src/errors.rs
@@ -1,5 +1,6 @@
use rustc_errors::{
- AddToDiagnostic, EmissionGuarantee, IntoDiagnostic, MultiSpan, SingleLabelManySpans,
+ AddToDiagnostic, DiagnosticBuilder, EmissionGuarantee, Handler, IntoDiagnostic, MultiSpan,
+ SingleLabelManySpans,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
use rustc_span::{symbol::Ident, Span, Symbol};
@@ -370,11 +371,12 @@ pub(crate) struct EnvNotDefined {
// Hand-written implementation to support custom user messages
impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for EnvNotDefined {
#[track_caller]
- fn into_diagnostic(
- self,
- handler: &'a rustc_errors::Handler,
- ) -> rustc_errors::DiagnosticBuilder<'a, G> {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
let mut diag = if let Some(msg) = self.msg {
+ #[expect(
+ rustc::untranslatable_diagnostic,
+ reason = "cannot translate user-provided messages"
+ )]
handler.struct_diagnostic(msg.as_str())
} else {
handler.struct_diagnostic(crate::fluent_generated::builtin_macros_env_not_defined)
@@ -551,3 +553,182 @@ pub(crate) struct FormatPositionalMismatch {
#[subdiagnostic]
pub(crate) highlight: SingleLabelManySpans,
}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_case_non_item)]
+pub(crate) struct TestCaseNonItem {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_bad_fn)]
+pub(crate) struct TestBadFn {
+ #[primary_span]
+ pub(crate) span: Span,
+ #[label]
+ pub(crate) cause: Span,
+ pub(crate) kind: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_explicit_register_name)]
+pub(crate) struct AsmExplicitRegisterName {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_mutually_exclusive)]
+pub(crate) struct AsmMutuallyExclusive {
+ #[primary_span]
+ pub(crate) spans: Vec<Span>,
+ pub(crate) opt1: &'static str,
+ pub(crate) opt2: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_pure_combine)]
+pub(crate) struct AsmPureCombine {
+ #[primary_span]
+ pub(crate) spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_pure_no_output)]
+pub(crate) struct AsmPureNoOutput {
+ #[primary_span]
+ pub(crate) spans: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_modifier_invalid)]
+pub(crate) struct AsmModifierInvalid {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_requires_template)]
+pub(crate) struct AsmRequiresTemplate {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_expected_comma)]
+pub(crate) struct AsmExpectedComma {
+ #[primary_span]
+ #[label]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_underscore_input)]
+pub(crate) struct AsmUnderscoreInput {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_sym_no_path)]
+pub(crate) struct AsmSymNoPath {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_expected_other)]
+pub(crate) struct AsmExpectedOther {
+ #[primary_span]
+ #[label(builtin_macros_asm_expected_other)]
+ pub(crate) span: Span,
+ pub(crate) is_global_asm: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_duplicate_arg)]
+pub(crate) struct AsmDuplicateArg {
+ #[primary_span]
+ #[label(builtin_macros_arg)]
+ pub(crate) span: Span,
+ #[label]
+ pub(crate) prev: Span,
+ pub(crate) name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_pos_after)]
+pub(crate) struct AsmPositionalAfter {
+ #[primary_span]
+ #[label(builtin_macros_pos)]
+ pub(crate) span: Span,
+ #[label(builtin_macros_named)]
+ pub(crate) named: Vec<Span>,
+ #[label(builtin_macros_explicit)]
+ pub(crate) explicit: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_noreturn)]
+pub(crate) struct AsmNoReturn {
+ #[primary_span]
+ pub(crate) outputs_sp: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_global_asm_clobber_abi)]
+pub(crate) struct GlobalAsmClobberAbi {
+ #[primary_span]
+ pub(crate) spans: Vec<Span>,
+}
+
+pub(crate) struct AsmClobberNoReg {
+ pub(crate) spans: Vec<Span>,
+ pub(crate) clobbers: Vec<Span>,
+}
+
+impl<'a, G: EmissionGuarantee> IntoDiagnostic<'a, G> for AsmClobberNoReg {
+ fn into_diagnostic(self, handler: &'a Handler) -> DiagnosticBuilder<'a, G> {
+ let mut diag =
+ handler.struct_diagnostic(crate::fluent_generated::builtin_macros_asm_clobber_no_reg);
+ diag.set_span(self.spans.clone());
+ // eager translation as `span_labels` takes `AsRef<str>`
+ let lbl1 = handler.eagerly_translate_to_string(
+ crate::fluent_generated::builtin_macros_asm_clobber_abi,
+ [].into_iter(),
+ );
+ diag.span_labels(self.clobbers, &lbl1);
+ let lbl2 = handler.eagerly_translate_to_string(
+ crate::fluent_generated::builtin_macros_asm_clobber_outputs,
+ [].into_iter(),
+ );
+ diag.span_labels(self.spans, &lbl2);
+ diag
+ }
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_asm_opt_already_provided)]
+pub(crate) struct AsmOptAlreadyprovided {
+ #[primary_span]
+ #[label]
+ pub(crate) span: Span,
+ pub(crate) symbol: Symbol,
+ #[suggestion(code = "", applicability = "machine-applicable", style = "tool-only")]
+ pub(crate) full_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_runner_invalid)]
+pub(crate) struct TestRunnerInvalid {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(builtin_macros_test_runner_nargs)]
+pub(crate) struct TestRunnerNargs {
+ #[primary_span]
+ pub(crate) span: Span,
+}
diff --git a/compiler/rustc_builtin_macros/src/format.rs b/compiler/rustc_builtin_macros/src/format.rs
index f0fc61d7c..c59a733c0 100644
--- a/compiler/rustc_builtin_macros/src/format.rs
+++ b/compiler/rustc_builtin_macros/src/format.rs
@@ -141,13 +141,7 @@ fn parse_args<'a>(ecx: &mut ExtCtxt<'a>, sp: Span, tts: TokenStream) -> PResult<
args: args
.named_args()
.iter()
- .filter_map(|a| {
- if let Some(ident) = a.kind.ident() {
- Some((a, ident))
- } else {
- None
- }
- })
+ .filter_map(|a| a.kind.ident().map(|ident| (a, ident)))
.map(|(arg, n)| n.span.to(arg.expr.span))
.collect(),
});
@@ -622,14 +616,14 @@ fn report_missing_placeholders(
} else {
diag.span_note(
sp,
- &format!("format specifiers use curly braces, and {}", trn),
+ format!("format specifiers use curly braces, and {}", trn),
);
}
} else {
if success {
- diag.help(&format!("`{}` should be written as `{}`", sub, trn));
+ diag.help(format!("`{}` should be written as `{}`", sub, trn));
} else {
- diag.note(&format!("`{}` should use curly braces, and {}", sub, trn));
+ diag.note(format!("`{}` should use curly braces, and {}", sub, trn));
}
}
}
@@ -783,7 +777,7 @@ fn report_invalid_references(
has_precision_star = true;
e.span_label(
*span,
- &format!(
+ format!(
"this precision flag adds an extra required argument at position {}, which is why there {} expected",
index,
if num_placeholders == 1 {
@@ -820,7 +814,7 @@ fn report_invalid_references(
};
e = ecx.struct_span_err(
span,
- &format!("invalid reference to positional {} ({})", arg_list, num_args_desc),
+ format!("invalid reference to positional {} ({})", arg_list, num_args_desc),
);
e.note("positional arguments are zero-based");
}
diff --git a/compiler/rustc_builtin_macros/src/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs
index bd9e903b6..bd5356575 100644
--- a/compiler/rustc_builtin_macros/src/format_foreign.rs
+++ b/compiler/rustc_builtin_macros/src/format_foreign.rs
@@ -562,15 +562,13 @@ pub(crate) mod printf {
}
if let Type = state {
- drop(c);
type_ = at.slice_between(next).unwrap();
// Don't use `move_to!` here, as we *can* be at the end of the input.
at = next;
}
- drop(c);
- drop(next);
+ let _ = c; // to avoid never used value
end = at;
let position = InnerSpan::new(start.at, end.at);
diff --git a/compiler/rustc_builtin_macros/src/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs
index 866cc5adb..f0d378d12 100644
--- a/compiler/rustc_builtin_macros/src/global_allocator.rs
+++ b/compiler/rustc_builtin_macros/src/global_allocator.rs
@@ -1,7 +1,7 @@
use crate::util::check_builtin_macro_attribute;
use rustc_ast::expand::allocator::{
- AllocatorKind, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
+ global_fn_name, AllocatorMethod, AllocatorTy, ALLOCATOR_METHODS,
};
use rustc_ast::ptr::P;
use rustc_ast::{self as ast, AttrVec, Expr, FnHeader, FnSig, Generics, Param, StmtKind};
@@ -40,8 +40,7 @@ pub fn expand(
// Generate a bunch of new items using the AllocFnFactory
let span = ecx.with_def_site_ctxt(item.span);
- let f =
- AllocFnFactory { span, ty_span, kind: AllocatorKind::Global, global: item.ident, cx: ecx };
+ let f = AllocFnFactory { span, ty_span, global: item.ident, cx: ecx };
// Generate item statements for the allocator methods.
let stmts = ALLOCATOR_METHODS.iter().map(|method| f.allocator_fn(method)).collect();
@@ -63,7 +62,6 @@ pub fn expand(
struct AllocFnFactory<'a, 'b> {
span: Span,
ty_span: Span,
- kind: AllocatorKind,
global: Ident,
cx: &'b ExtCtxt<'a>,
}
@@ -92,7 +90,7 @@ impl AllocFnFactory<'_, '_> {
}));
let item = self.cx.item(
self.span,
- Ident::from_str_and_span(&self.kind.fn_name(method.name), self.span),
+ Ident::from_str_and_span(&global_fn_name(method.name), self.span),
self.attrs(),
kind,
);
diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs
index 37fbd03a6..ebf1448f5 100644
--- a/compiler/rustc_builtin_macros/src/lib.rs
+++ b/compiler/rustc_builtin_macros/src/lib.rs
@@ -1,7 +1,6 @@
//! This crate contains implementations of built-in macros and other code generating facilities
//! injecting code into the crate before it is lowered to HIR.
-#![allow(rustc::potential_query_instability)]
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
#![feature(array_windows)]
#![feature(box_patterns)]
@@ -24,7 +23,7 @@ use crate::deriving::*;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind};
use rustc_expand::proc_macro::BangProcMacro;
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
use rustc_span::symbol::sym;
mod alloc_error_handler;
@@ -116,6 +115,7 @@ pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) {
register_derive! {
Clone: clone::expand_deriving_clone,
Copy: bounds::expand_deriving_copy,
+ ConstParamTy: bounds::expand_deriving_const_param_ty,
Debug: debug::expand_deriving_debug,
Default: default::expand_deriving_default,
Eq: eq::expand_deriving_eq,
diff --git a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
index 378d5f39f..52b5601bb 100644
--- a/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
+++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs
@@ -194,7 +194,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
};
self.handler
- .struct_span_err(attr.span, &msg)
+ .struct_span_err(attr.span, msg)
.span_label(prev_attr.span, "previous attribute here")
.emit();
@@ -219,7 +219,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
pprust::path_to_string(&attr.get_normal_item().path),
);
- self.handler.span_err(attr.span, &msg);
+ self.handler.span_err(attr.span, msg);
return;
}
@@ -233,7 +233,7 @@ impl<'a> Visitor<'a> for CollectProcMacros<'a> {
pprust::path_to_string(&attr.get_normal_item().path),
);
- self.handler.span_err(attr.span, &msg);
+ self.handler.span_err(attr.span, msg);
return;
}
diff --git a/compiler/rustc_builtin_macros/src/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs
index 0b17e92ef..e613b904d 100644
--- a/compiler/rustc_builtin_macros/src/source_util.rs
+++ b/compiler/rustc_builtin_macros/src/source_util.rs
@@ -150,7 +150,7 @@ pub fn expand_include<'cx>(
if self.p.token != token::Eof {
let token = pprust::token_to_string(&self.p.token);
let msg = format!("expected item, found `{}`", token);
- self.p.struct_span_err(self.p.token.span, &msg).emit();
+ self.p.struct_span_err(self.p.token.span, msg).emit();
}
break;
@@ -188,12 +188,12 @@ pub fn expand_include_str(
base::MacEager::expr(cx.expr_str(sp, interned_src))
}
Err(_) => {
- cx.span_err(sp, &format!("{} wasn't a utf-8 file", file.display()));
+ cx.span_err(sp, format!("{} wasn't a utf-8 file", file.display()));
DummyResult::any(sp)
}
},
Err(e) => {
- cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
+ cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp)
}
}
@@ -221,7 +221,7 @@ pub fn expand_include_bytes(
base::MacEager::expr(expr)
}
Err(e) => {
- cx.span_err(sp, &format!("couldn't read {}: {}", file.display(), e));
+ cx.span_err(sp, format!("couldn't read {}: {}", file.display(), e));
DummyResult::any(sp)
}
}
diff --git a/compiler/rustc_builtin_macros/src/test.rs b/compiler/rustc_builtin_macros/src/test.rs
index 79d8be248..49ee276af 100644
--- a/compiler/rustc_builtin_macros/src/test.rs
+++ b/compiler/rustc_builtin_macros/src/test.rs
@@ -1,3 +1,4 @@
+use crate::errors;
/// The expansion from a test function to the appropriate test struct for libtest
/// Ideally, this code would be in libtest but for efficiency and error messages it lives here.
use crate::util::{check_builtin_macro_attribute, warn_on_duplicate_attribute};
@@ -40,12 +41,7 @@ pub fn expand_test_case(
unreachable!()
},
_ => {
- ecx.struct_span_err(
- anno_item.span(),
- "`#[test_case]` attribute is only allowed on items",
- )
- .emit();
-
+ ecx.emit_err(errors::TestCaseNonItem { span: anno_item.span() });
return vec![];
}
};
@@ -533,15 +529,11 @@ fn has_test_signature(cx: &ExtCtxt<'_>, i: &ast::Item) -> bool {
match &i.kind {
ast::ItemKind::Fn(box ast::Fn { sig, generics, .. }) => {
if let ast::Unsafe::Yes(span) = sig.header.unsafety {
- sd.struct_span_err(i.span, "unsafe functions cannot be used for tests")
- .span_label(span, "`unsafe` because of this")
- .emit();
+ sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "unsafe" });
return false;
}
if let ast::Async::Yes { span, .. } = sig.header.asyncness {
- sd.struct_span_err(i.span, "async functions cannot be used for tests")
- .span_label(span, "`async` because of this")
- .emit();
+ sd.emit_err(errors::TestBadFn { span: i.span, cause: span, kind: "async" });
return false;
}
diff --git a/compiler/rustc_builtin_macros/src/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs
index 80f497333..9bc1e27b4 100644
--- a/compiler/rustc_builtin_macros/src/test_harness.rs
+++ b/compiler/rustc_builtin_macros/src/test_harness.rs
@@ -19,6 +19,8 @@ use tracing::debug;
use std::{iter, mem};
+use crate::errors;
+
#[derive(Clone)]
struct Test {
span: Span,
@@ -230,7 +232,7 @@ fn generate_test_harness(
let expn_id = ext_cx.resolver.expansion_for_ast_pass(
DUMMY_SP,
AstPass::TestHarness,
- &[sym::test, sym::rustc_attrs],
+ &[sym::test, sym::rustc_attrs, sym::no_coverage],
None,
);
let def_site = DUMMY_SP.with_def_site_ctxt(expn_id.to_expn_id());
@@ -311,6 +313,8 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
// #[rustc_main]
let main_attr = ecx.attr_word(sym::rustc_main, sp);
+ // #[no_coverage]
+ let no_coverage_attr = ecx.attr_word(sym::no_coverage, sp);
// pub fn main() { ... }
let main_ret_ty = ecx.ty(sp, ast::TyKind::Tup(ThinVec::new()));
@@ -340,7 +344,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P<ast::Item> {
let main = P(ast::Item {
ident: main_id,
- attrs: thin_vec![main_attr],
+ attrs: thin_vec![main_attr, no_coverage_attr],
id: ast::DUMMY_NODE_ID,
kind: main,
vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None },
@@ -385,11 +389,11 @@ fn get_test_runner(sd: &rustc_errors::Handler, krate: &ast::Crate) -> Option<ast
[single] => match single.meta_item() {
Some(meta_item) if meta_item.is_word() => return Some(meta_item.path.clone()),
_ => {
- sd.struct_span_err(span, "`test_runner` argument must be a path").emit();
+ sd.emit_err(errors::TestRunnerInvalid { span });
}
},
_ => {
- sd.struct_span_err(span, "`#![test_runner(..)]` accepts exactly 1 argument").emit();
+ sd.emit_err(errors::TestRunnerNargs { span });
}
}
None
diff --git a/compiler/rustc_builtin_macros/src/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs
index cc5ae6894..9c98723e1 100644
--- a/compiler/rustc_builtin_macros/src/trace_macros.rs
+++ b/compiler/rustc_builtin_macros/src/trace_macros.rs
@@ -8,7 +8,7 @@ pub fn expand_trace_macros(
sp: Span,
tt: TokenStream,
) -> Box<dyn base::MacResult + 'static> {
- let mut cursor = tt.into_trees();
+ let mut cursor = tt.trees();
let mut err = false;
let value = match &cursor.next() {
Some(TokenTree::Token(token, _)) if token.is_keyword(kw::True) => true,
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md b/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md
new file mode 100644
index 000000000..c70ba8f49
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/README.md
@@ -0,0 +1,18 @@
+# github-release
+
+An action used to publish GitHub releases for `wasmtime`.
+
+As of the time of this writing there's a few actions floating around which
+perform github releases but they all tend to have their set of drawbacks.
+Additionally nothing handles deleting releases which we need for our rolling
+`dev` release.
+
+To handle all this this action rolls-its-own implementation using the
+actions/toolkit repository and packages published there. These run in a Docker
+container and take various inputs to orchestrate the release from the build.
+
+More comments can be found in `main.js`.
+
+Testing this is really hard. If you want to try though run `npm install` and
+then `node main.js`. You'll have to configure a bunch of env vars though to get
+anything reasonably working.
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml b/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml
new file mode 100644
index 000000000..36e5209f5
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/action.yml
@@ -0,0 +1,13 @@
+# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+name: 'rustc_codegen_cranelift github releases'
+description: 'rustc_codegen_cranelift github releases'
+inputs:
+ token:
+ description: ''
+ required: true
+ files:
+ description: ''
+ required: true
+runs:
+ using: 'node16'
+ main: 'main.js'
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
new file mode 100644
index 000000000..6fcfca34e
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/main.js
@@ -0,0 +1,162 @@
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+
+const core = require('@actions/core');
+const path = require("path");
+const fs = require("fs");
+const github = require('@actions/github');
+const glob = require('glob');
+
+function sleep(milliseconds) {
+ return new Promise(resolve => setTimeout(resolve, milliseconds))
+}
+
+async function runOnce() {
+ // Load all our inputs and env vars. Note that `getInput` reads from `INPUT_*`
+ const files = core.getInput('files');
+ const token = core.getInput('token');
+ const slug = process.env.GITHUB_REPOSITORY;
+ const owner = slug.split('/')[0];
+ const repo = slug.split('/')[1];
+ const sha = process.env.GITHUB_SHA;
+ let name = 'dev';
+ if (process.env.GITHUB_REF.startsWith('refs/tags/v')) {
+ name = process.env.GITHUB_REF.substring(10);
+ }
+
+ core.info(`files: ${files}`);
+ core.info(`name: ${name}`);
+ core.info(`token: ${token}`);
+
+ const octokit = github.getOctokit(token);
+
+ // For the `dev` release we may need to update the tag to point to the new
+ // commit on this branch. All other names should already have tags associated
+ // with them.
+ if (name == 'dev') {
+ let tag = null;
+ try {
+ tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name });
+ core.info(`found existing tag`);
+ console.log("tag: ", JSON.stringify(tag.data, null, 2));
+ } catch (e) {
+ // ignore if this tag doesn't exist
+ core.info(`no existing tag found`);
+ }
+
+ if (tag === null || tag.data.object.sha !== sha) {
+ core.info(`updating existing tag or creating new one`);
+
+ try {
+ core.info(`updating dev tag`);
+ await octokit.rest.git.updateRef({
+ owner,
+ repo,
+ ref: 'tags/dev',
+ sha,
+ force: true,
+ });
+ } catch (e) {
+ console.log("ERROR: ", JSON.stringify(e.data, null, 2));
+ core.info(`creating dev tag`);
+ try {
+ await octokit.rest.git.createRef({
+ owner,
+ repo,
+ ref: 'refs/tags/dev',
+ sha,
+ });
+ } catch (e) {
+ // we might race with others, so assume someone else has created the
+ // tag by this point.
+ console.log("failed to create tag: ", JSON.stringify(e.data, null, 2));
+ }
+ }
+
+ console.log("double-checking tag is correct");
+ tag = await octokit.request("GET /repos/:owner/:repo/git/refs/tags/:name", { owner, repo, name });
+ if (tag.data.object.sha !== sha) {
+ console.log("tag: ", JSON.stringify(tag.data, null, 2));
+ throw new Error("tag didn't work");
+ }
+ } else {
+ core.info(`existing tag works`);
+ }
+ }
+
+ // Delete a previous release
+ try {
+ core.info(`fetching release`);
+ let release = await octokit.rest.repos.getReleaseByTag({ owner, repo, tag: name });
+ console.log("found release: ", JSON.stringify(release.data, null, 2));
+ await octokit.rest.repos.deleteRelease({
+ owner,
+ repo,
+ release_id: release.data.id,
+ });
+ console.log("deleted release");
+ } catch (e) {
+ console.log("ERROR: ", JSON.stringify(e, null, 2));
+ }
+
+ console.log("creating a release");
+ let release = await octokit.rest.repos.createRelease({
+ owner,
+ repo,
+ tag_name: name,
+ prerelease: name === 'dev',
+ });
+
+ // Delete all assets from a previous run
+ for (const asset of release.data.assets) {
+ console.log(`deleting prior asset ${asset.id}`);
+ await octokit.rest.repos.deleteReleaseAsset({
+ owner,
+ repo,
+ asset_id: asset.id,
+ });
+ }
+
+ // Upload all the relevant assets for this release as just general blobs.
+ for (const file of glob.sync(files)) {
+ const size = fs.statSync(file).size;
+ const name = path.basename(file);
+ core.info(`upload ${file}`);
+ await octokit.rest.repos.uploadReleaseAsset({
+ data: fs.createReadStream(file),
+ headers: { 'content-length': size, 'content-type': 'application/octet-stream' },
+ name,
+ url: release.data.upload_url,
+ });
+ }
+}
+
+async function run() {
+ const retries = 10;
+ for (let i = 0; i < retries; i++) {
+ try {
+ await runOnce();
+ break;
+ } catch (e) {
+ if (i === retries - 1)
+ throw e;
+ logError(e);
+ console.log("RETRYING after 10s");
+ await sleep(10000)
+ }
+ }
+}
+
+function logError(e) {
+ console.log("ERROR: ", e.message);
+ try {
+ console.log(JSON.stringify(e, null, 2));
+ } catch (e) {
+ // ignore json errors for now
+ }
+ console.log(e.stack);
+}
+
+run().catch(err => {
+ logError(err);
+ core.setFailed(err.message);
+});
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json
new file mode 100644
index 000000000..dd3b2a048
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package-lock.json
@@ -0,0 +1,571 @@
+{
+ "name": "rustc_codegen_cranelift-github-release",
+ "version": "0.0.0",
+ "lockfileVersion": 2,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "rustc_codegen_cranelift-github-release",
+ "version": "0.0.0",
+ "dependencies": {
+ "@actions/core": "^1.9.1",
+ "@actions/github": "^5.1.0",
+ "glob": "^7.1.5"
+ }
+ },
+ "node_modules/@actions/core": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
+ "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+ "dependencies": {
+ "@actions/http-client": "^2.0.1",
+ "uuid": "^8.3.2"
+ }
+ },
+ "node_modules/@actions/github": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz",
+ "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==",
+ "dependencies": {
+ "@actions/http-client": "^2.0.1",
+ "@octokit/core": "^3.6.0",
+ "@octokit/plugin-paginate-rest": "^2.17.0",
+ "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
+ }
+ },
+ "node_modules/@actions/http-client": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+ "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
+ "dependencies": {
+ "tunnel": "^0.0.6"
+ }
+ },
+ "node_modules/@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "node_modules/@octokit/core": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+ "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+ "dependencies": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.3",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "dependencies": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/openapi-types": {
+ "version": "12.11.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
+ "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
+ },
+ "node_modules/@octokit/plugin-paginate-rest": {
+ "version": "2.21.3",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+ "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+ "dependencies": {
+ "@octokit/types": "^6.40.0"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=2"
+ }
+ },
+ "node_modules/@octokit/plugin-rest-endpoint-methods": {
+ "version": "5.16.2",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
+ "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
+ "dependencies": {
+ "@octokit/types": "^6.39.0",
+ "deprecation": "^2.3.1"
+ },
+ "peerDependencies": {
+ "@octokit/core": ">=3"
+ }
+ },
+ "node_modules/@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "dependencies": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "node_modules/@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "dependencies": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/@octokit/types": {
+ "version": "6.41.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
+ "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
+ "dependencies": {
+ "@octokit/openapi-types": "^12.11.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "node_modules/before-after-hook": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
+ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
+ },
+ "node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "node_modules/deprecation": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "dependencies": {
+ "whatwg-url": "^5.0.0"
+ },
+ "engines": {
+ "node": "4.x || >=6.0.0"
+ },
+ "peerDependencies": {
+ "encoding": "^0.1.0"
+ },
+ "peerDependenciesMeta": {
+ "encoding": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "node_modules/tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg==",
+ "engines": {
+ "node": ">=0.6.11 <=0.7.0 || >=0.7.3"
+ }
+ },
+ "node_modules/universal-user-agent": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+ },
+ "node_modules/uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==",
+ "bin": {
+ "uuid": "dist/bin/uuid"
+ }
+ },
+ "node_modules/webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "node_modules/whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "dependencies": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "node_modules/wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ }
+ },
+ "dependencies": {
+ "@actions/core": {
+ "version": "1.9.1",
+ "resolved": "https://registry.npmjs.org/@actions/core/-/core-1.9.1.tgz",
+ "integrity": "sha512-5ad+U2YGrmmiw6du20AQW5XuWo7UKN2052FjSV7MX+Wfjf8sCqcsZe62NfgHys4QI4/Y+vQvLKYL8jWtA1ZBTA==",
+ "requires": {
+ "@actions/http-client": "^2.0.1",
+ "uuid": "^8.3.2"
+ }
+ },
+ "@actions/github": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/@actions/github/-/github-5.1.0.tgz",
+ "integrity": "sha512-tuI80F7JQIhg77ZTTgUAPpVD7ZnP9oHSPN8xw7LOwtA4vEMbAjWJNbmLBfV7xua7r016GyjzWLuec5cs8f/a8A==",
+ "requires": {
+ "@actions/http-client": "^2.0.1",
+ "@octokit/core": "^3.6.0",
+ "@octokit/plugin-paginate-rest": "^2.17.0",
+ "@octokit/plugin-rest-endpoint-methods": "^5.13.0"
+ }
+ },
+ "@actions/http-client": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/@actions/http-client/-/http-client-2.0.1.tgz",
+ "integrity": "sha512-PIXiMVtz6VvyaRsGY268qvj57hXQEpsYogYOu2nrQhlf+XCGmZstmuZBbAybUl1nQGnvS1k1eEsQ69ZoD7xlSw==",
+ "requires": {
+ "tunnel": "^0.0.6"
+ }
+ },
+ "@octokit/auth-token": {
+ "version": "2.5.0",
+ "resolved": "https://registry.npmjs.org/@octokit/auth-token/-/auth-token-2.5.0.tgz",
+ "integrity": "sha512-r5FVUJCOLl19AxiuZD2VRZ/ORjp/4IN98Of6YJoJOkY75CIBuYfmiNHGrDwXr+aLGG55igl9QrxX3hbiXlLb+g==",
+ "requires": {
+ "@octokit/types": "^6.0.3"
+ }
+ },
+ "@octokit/core": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/@octokit/core/-/core-3.6.0.tgz",
+ "integrity": "sha512-7RKRKuA4xTjMhY+eG3jthb3hlZCsOwg3rztWh75Xc+ShDWOfDDATWbeZpAHBNRpm4Tv9WgBMOy1zEJYXG6NJ7Q==",
+ "requires": {
+ "@octokit/auth-token": "^2.4.4",
+ "@octokit/graphql": "^4.5.8",
+ "@octokit/request": "^5.6.3",
+ "@octokit/request-error": "^2.0.5",
+ "@octokit/types": "^6.0.3",
+ "before-after-hook": "^2.2.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/endpoint": {
+ "version": "6.0.12",
+ "resolved": "https://registry.npmjs.org/@octokit/endpoint/-/endpoint-6.0.12.tgz",
+ "integrity": "sha512-lF3puPwkQWGfkMClXb4k/eUT/nZKQfxinRWJrdZaJO85Dqwo/G0yOC434Jr2ojwafWJMYqFGFa5ms4jJUgujdA==",
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "is-plain-object": "^5.0.0",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/graphql": {
+ "version": "4.8.0",
+ "resolved": "https://registry.npmjs.org/@octokit/graphql/-/graphql-4.8.0.tgz",
+ "integrity": "sha512-0gv+qLSBLKF0z8TKaSKTsS39scVKF9dbMxJpj3U0vC7wjNWFuIpL/z76Qe2fiuCbDRcJSavkXsVtMS6/dtQQsg==",
+ "requires": {
+ "@octokit/request": "^5.6.0",
+ "@octokit/types": "^6.0.3",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/openapi-types": {
+ "version": "12.11.0",
+ "resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-12.11.0.tgz",
+ "integrity": "sha512-VsXyi8peyRq9PqIz/tpqiL2w3w80OgVMwBHltTml3LmVvXiphgeqmY9mvBw9Wu7e0QWk/fqD37ux8yP5uVekyQ=="
+ },
+ "@octokit/plugin-paginate-rest": {
+ "version": "2.21.3",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-2.21.3.tgz",
+ "integrity": "sha512-aCZTEf0y2h3OLbrgKkrfFdjRL6eSOo8komneVQJnYecAxIej7Bafor2xhuDJOIFau4pk0i/P28/XgtbyPF0ZHw==",
+ "requires": {
+ "@octokit/types": "^6.40.0"
+ }
+ },
+ "@octokit/plugin-rest-endpoint-methods": {
+ "version": "5.16.2",
+ "resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-5.16.2.tgz",
+ "integrity": "sha512-8QFz29Fg5jDuTPXVtey05BLm7OB+M8fnvE64RNegzX7U+5NUXcOcnpTIK0YfSHBg8gYd0oxIq3IZTe9SfPZiRw==",
+ "requires": {
+ "@octokit/types": "^6.39.0",
+ "deprecation": "^2.3.1"
+ }
+ },
+ "@octokit/request": {
+ "version": "5.6.3",
+ "resolved": "https://registry.npmjs.org/@octokit/request/-/request-5.6.3.tgz",
+ "integrity": "sha512-bFJl0I1KVc9jYTe9tdGGpAMPy32dLBXXo1dS/YwSCTL/2nd9XeHsY616RE3HPXDVk+a+dBuzyz5YdlXwcDTr2A==",
+ "requires": {
+ "@octokit/endpoint": "^6.0.1",
+ "@octokit/request-error": "^2.1.0",
+ "@octokit/types": "^6.16.1",
+ "is-plain-object": "^5.0.0",
+ "node-fetch": "^2.6.7",
+ "universal-user-agent": "^6.0.0"
+ }
+ },
+ "@octokit/request-error": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/@octokit/request-error/-/request-error-2.1.0.tgz",
+ "integrity": "sha512-1VIvgXxs9WHSjicsRwq8PlR2LR2x6DwsJAaFgzdi0JfJoGSO8mYI/cHJQ+9FbN21aa+DrgNLnwObmyeSC8Rmpg==",
+ "requires": {
+ "@octokit/types": "^6.0.3",
+ "deprecation": "^2.0.0",
+ "once": "^1.4.0"
+ }
+ },
+ "@octokit/types": {
+ "version": "6.41.0",
+ "resolved": "https://registry.npmjs.org/@octokit/types/-/types-6.41.0.tgz",
+ "integrity": "sha512-eJ2jbzjdijiL3B4PrSQaSjuF2sPEQPVCPzBvTHJD9Nz+9dw2SGH4K4xeQJ77YfTq5bRQ+bD8wT11JbeDPmxmGg==",
+ "requires": {
+ "@octokit/openapi-types": "^12.11.0"
+ }
+ },
+ "balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw=="
+ },
+ "before-after-hook": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/before-after-hook/-/before-after-hook-2.2.3.tgz",
+ "integrity": "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="
+ },
+ "brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "requires": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg=="
+ },
+ "deprecation": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/deprecation/-/deprecation-2.3.1.tgz",
+ "integrity": "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="
+ },
+ "fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw=="
+ },
+ "glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "requires": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ }
+ },
+ "inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "requires": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
+ },
+ "is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q=="
+ },
+ "minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "requires": {
+ "brace-expansion": "^1.1.7"
+ }
+ },
+ "node-fetch": {
+ "version": "2.6.7",
+ "resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.7.tgz",
+ "integrity": "sha512-ZjMPFEfVx5j+y2yF35Kzx5sF7kDzxuDj6ziH4FFbOp87zKDZNx8yExJIb05OGF4Nlt9IHFIMBkRl41VdvcNdbQ==",
+ "requires": {
+ "whatwg-url": "^5.0.0"
+ }
+ },
+ "once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "requires": {
+ "wrappy": "1"
+ }
+ },
+ "path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg=="
+ },
+ "tr46": {
+ "version": "0.0.3",
+ "resolved": "https://registry.npmjs.org/tr46/-/tr46-0.0.3.tgz",
+ "integrity": "sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw=="
+ },
+ "tunnel": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/tunnel/-/tunnel-0.0.6.tgz",
+ "integrity": "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="
+ },
+ "universal-user-agent": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/universal-user-agent/-/universal-user-agent-6.0.0.tgz",
+ "integrity": "sha512-isyNax3wXoKaulPDZWHQqbmIx1k2tb9fb3GGDBRxCscfYV2Ch7WxPArBsFEG8s/safwXTT7H4QGhaIkTp9447w=="
+ },
+ "uuid": {
+ "version": "8.3.2",
+ "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz",
+ "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg=="
+ },
+ "webidl-conversions": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/webidl-conversions/-/webidl-conversions-3.0.1.tgz",
+ "integrity": "sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ=="
+ },
+ "whatwg-url": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/whatwg-url/-/whatwg-url-5.0.0.tgz",
+ "integrity": "sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==",
+ "requires": {
+ "tr46": "~0.0.3",
+ "webidl-conversions": "^3.0.0"
+ }
+ },
+ "wrappy": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
+ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="
+ }
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json
new file mode 100644
index 000000000..d9c23f887
--- /dev/null
+++ b/compiler/rustc_codegen_cranelift/.github/actions/github-release/package.json
@@ -0,0 +1,11 @@
+{
+ "name": "rustc_codegen_cranelift-github-release",
+ "version": "0.0.0",
+ "license": "Apache-2.0 WITH LLVM-exception",
+ "main": "main.js",
+ "dependencies": {
+ "@actions/core": "^1.9.1",
+ "@actions/github": "^5.1.0",
+ "glob": "^7.1.5"
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
index 5f5510a57..3c4055566 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/abi-cafe.yml
@@ -45,13 +45,6 @@ jobs:
if: matrix.env.TARGET_TRIPLE == 'x86_64-pc-windows-gnu'
run: rustup set default-host x86_64-pc-windows-gnu
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Prepare dependencies
run: ./y.rs prepare
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
index 98b34c65d..e4af73ea6 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/main.yml
@@ -20,6 +20,7 @@ jobs:
run: |
cargo fmt --check
rustfmt --check build_system/mod.rs
+ rustfmt --check example/*
test:
@@ -89,13 +90,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-s390x-linux-gnu qemu-user
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Prepare dependencies
run: ./y.rs prepare
@@ -137,13 +131,6 @@ jobs:
path: ~/.cargo/bin
key: ${{ runner.os }}-${{ matrix.env.TARGET_TRIPLE }}-cargo-bin-dir-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Install hyperfine
run: cargo install hyperfine || true
@@ -206,13 +193,6 @@ jobs:
sudo apt-get update
sudo apt-get install -y gcc-mingw-w64-x86-64 wine-stable
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Prepare dependencies
run: ./y.rs prepare
@@ -238,3 +218,43 @@ jobs:
with:
name: cg_clif-${{ runner.os }}-cross-x86_64-mingw
path: cg_clif.tar.xz
+
+ release:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ if: ${{ github.ref == 'refs/heads/master' }}
+ needs: [rustfmt, test, bench, dist]
+
+ concurrency:
+ group: release-dev
+ cancel-in-progress: true
+
+ steps:
+ - uses: actions/checkout@v3
+
+ - name: Download all built artifacts
+ uses: actions/download-artifact@v3
+ with:
+ path: artifacts/
+
+ - run: |
+ ls -R artifacts/
+ mkdir release/
+ pushd artifacts/
+ for dir in *; do
+ mv $dir/cg_clif.tar.xz ../release/$dir.tar.xz
+ rmdir $dir/ # verify $dir is empty
+ done
+ popd
+ rmdir artifacts/ # verify all artifacts are represented in release/
+ ls -R release/
+
+ - run: npm install --production
+ working-directory: .github/actions/github-release
+
+ - name: Publish Release
+ uses: ./.github/actions/github-release
+ with:
+ files: "release/*"
+ token: ${{ github.token }}
+ continue-on-error: true
diff --git a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
index 5faa8f054..b2f772c4f 100644
--- a/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
+++ b/compiler/rustc_codegen_cranelift/.github/workflows/rustc.yml
@@ -6,6 +6,7 @@ on:
jobs:
bootstrap_rustc:
runs-on: ubuntu-latest
+ timeout-minutes: 60
steps:
- uses: actions/checkout@v3
@@ -16,20 +17,16 @@ jobs:
path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Prepare dependencies
run: ./y.rs prepare
- name: Test
run: ./scripts/test_bootstrap.sh
+
+
rustc_test_suite:
runs-on: ubuntu-latest
+ timeout-minutes: 60
steps:
- uses: actions/checkout@v3
@@ -40,13 +37,6 @@ jobs:
path: build/cg_clif
key: ${{ runner.os }}-cargo-build-target-${{ hashFiles('rust-toolchain', '**/Cargo.lock') }}
- - name: Use sparse cargo registry
- run: |
- cat >> ~/.cargo/config.toml <<EOF
- [unstable]
- sparse-registry = true
- EOF
-
- name: Prepare dependencies
run: ./y.rs prepare
diff --git a/compiler/rustc_codegen_cranelift/Cargo.lock b/compiler/rustc_codegen_cranelift/Cargo.lock
index 87e4ac266..07a8e431a 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/Cargo.lock
@@ -4,11 +4,11 @@ version = 3
[[package]]
name = "ahash"
-version = "0.7.6"
+version = "0.8.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fcb51a0695d8f838b1ee009b3fbf66bda078cd64590202a864a8f3e8c4315c47"
+checksum = "2c99f64d1e06488f620f932677e24bc6e2897582980441ae90a671415bd7ec2f"
dependencies = [
- "getrandom",
+ "cfg-if",
"once_cell",
"version_check",
]
@@ -20,12 +20,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6"
[[package]]
-name = "arrayvec"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8da52d66c7071e2e3fa2a1e5c6d088fec47b593032b254f5e980de8ea54454d6"
-
-[[package]]
name = "autocfg"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -57,20 +51,19 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
[[package]]
name = "cranelift-bforest"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a7379abaacee0f14abf3204a7606118f0465785252169d186337bcb75030815a"
+checksum = "1277fbfa94bc82c8ec4af2ded3e639d49ca5f7f3c7eeab2c66accd135ece4e70"
dependencies = [
"cranelift-entity",
]
[[package]]
name = "cranelift-codegen"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9489fa336927df749631f1008007ced2871068544f40a202ce6d93fbf2366a7b"
+checksum = "c6e8c31ad3b2270e9aeec38723888fe1b0ace3bea2b06b3f749ccf46661d3220"
dependencies = [
- "arrayvec",
"bumpalo",
"cranelift-bforest",
"cranelift-codegen-meta",
@@ -78,7 +71,7 @@ dependencies = [
"cranelift-entity",
"cranelift-isle",
"gimli",
- "hashbrown",
+ "hashbrown 0.13.2",
"log",
"regalloc2",
"smallvec",
@@ -87,30 +80,30 @@ dependencies = [
[[package]]
name = "cranelift-codegen-meta"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05bbb67da91ec721ed57cef2f7c5ef7728e1cd9bde9ffd3ef8601022e73e3239"
+checksum = "c8ac5ac30d62b2d66f12651f6b606dbdfd9c2cfd0908de6b387560a277c5c9da"
dependencies = [
"cranelift-codegen-shared",
]
[[package]]
name = "cranelift-codegen-shared"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "418ecb2f36032f6665dc1a5e2060a143dbab41d83b784882e97710e890a7a16d"
+checksum = "dd82b8b376247834b59ed9bdc0ddeb50f517452827d4a11bccf5937b213748b8"
[[package]]
name = "cranelift-entity"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7cf583f7b093f291005f9fb1323e2c37f6ee4c7909e39ce016b2e8360d461705"
+checksum = "40099d38061b37e505e63f89bab52199037a72b931ad4868d9089ff7268660b0"
[[package]]
name = "cranelift-frontend"
-version = "0.93.0"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7d361ed0373cf5f086b49c499aa72227b646a64f899f32e34312f97c0fadff75"
+checksum = "64a25d9d0a0ae3079c463c34115ec59507b4707175454f0eee0891e83e30e82d"
dependencies = [
"cranelift-codegen",
"log",
@@ -120,15 +113,15 @@ dependencies = [
[[package]]
name = "cranelift-isle"
-version = "0.93.1"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "649782a39ce99798dd6b4029e2bb318a2fbeaade1b4fa25330763c10c65bc358"
+checksum = "80de6a7d0486e4acbd5f9f87ec49912bf4c8fb6aea00087b989685460d4469ba"
[[package]]
name = "cranelift-jit"
-version = "0.93.0"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c9909222db472fcc98d9e4e7192fa9d064dac63a3fa657df8c6daae86fb2604"
+checksum = "3ca96b05988aa057eda09a817a6e31915fabd7f476b513123aff08053cd193dd"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -145,9 +138,9 @@ dependencies = [
[[package]]
name = "cranelift-module"
-version = "0.93.0"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "68689b83e52e605ba48652882d3fccc2e2e136abf139eb64ae667888ba0d52f8"
+checksum = "e5112c0be9cc5da064e0620570d67852f11ce44f2e572a58ecf7f11df73978b8"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -155,9 +148,9 @@ dependencies = [
[[package]]
name = "cranelift-native"
-version = "0.93.0"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f98e4e99a353703475d5acb402b9c13482d41d8a4008b352559bd560afb90363"
+checksum = "bb6b03e0e03801c4b3fd8ce0758a94750c07a44e7944cc0ffbf0d3f2e7c79b00"
dependencies = [
"cranelift-codegen",
"libc",
@@ -166,9 +159,9 @@ dependencies = [
[[package]]
name = "cranelift-object"
-version = "0.93.0"
+version = "0.95.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b7a006ce1d8dd11df67567d8673e5920f3a56441812aed52a007ffce8f1b20e9"
+checksum = "48ed1b37d0972abe804cb5bf2b35f3a76a276ebbe148e3a726d8e31042790978"
dependencies = [
"anyhow",
"cranelift-codegen",
@@ -203,21 +196,10 @@ dependencies = [
]
[[package]]
-name = "getrandom"
-version = "0.2.8"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c05aeb6a22b8f62540c194aac980f2115af067bfe15a0734d7277a768d396b31"
-dependencies = [
- "cfg-if",
- "libc",
- "wasi",
-]
-
-[[package]]
name = "gimli"
-version = "0.26.2"
+version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
dependencies = [
"fallible-iterator",
"indexmap",
@@ -229,6 +211,12 @@ name = "hashbrown"
version = "0.12.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a9ee70c43aaf417c914396645a0fa852624801b24ebb7ae78fe8272889ac888"
+
+[[package]]
+name = "hashbrown"
+version = "0.13.2"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "43a3c133739dddd0d2990f9a4bdf8eb4b21ef50e4851ca85ab661199821d510e"
dependencies = [
"ahash",
]
@@ -240,7 +228,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bd070e393353796e801d209ad339e89596eb4c8d430d18ede6a1cced8fafbd99"
dependencies = [
"autocfg",
- "hashbrown",
+ "hashbrown 0.12.3",
]
[[package]]
@@ -285,12 +273,12 @@ checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d"
[[package]]
name = "object"
-version = "0.29.0"
+version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"crc32fast",
- "hashbrown",
+ "hashbrown 0.13.2",
"indexmap",
"memchr",
]
@@ -303,9 +291,9 @@ checksum = "86f0b0d4bf799edbc74508c1e8bf170ff5f41238e5f8225603ca7caaae2b7860"
[[package]]
name = "regalloc2"
-version = "0.5.1"
+version = "0.6.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "300d4fbfb40c1c66a78ba3ddd41c1110247cf52f97b87d0f2fc9209bd49b030c"
+checksum = "80535183cae11b149d618fbd3c37e38d7cda589d82d7769e196ca9a9042d7621"
dependencies = [
"fxhash",
"log",
@@ -375,16 +363,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
-[[package]]
name = "wasmtime-jit-icache-coherence"
-version = "6.0.0"
+version = "8.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ec1fd0f0dd79e7cc0f55b102e320d7c77ab76cd272008a8fd98e25b5777e2636"
+checksum = "aecae978b13f7f67efb23bd827373ace4578f2137ec110bbf6a4a7cde4121bbd"
dependencies = [
"cfg-if",
"libc",
@@ -415,9 +397,18 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "windows-sys"
-version = "0.42.0"
+version = "0.45.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "75283be5efb2831d37ea142365f009c02ec203cd29a3ebecbc093d52315b66d0"
+dependencies = [
+ "windows-targets",
+]
+
+[[package]]
+name = "windows-targets"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5a3e1820f08b8513f676f7ab6c1f99ff312fb97b553d30ff4dd86f9f15728aa7"
+checksum = "8e2522491fbfcd58cc84d47aeb2958948c4b8982e9a2d8a2a35bbaed431390e7"
dependencies = [
"windows_aarch64_gnullvm",
"windows_aarch64_msvc",
@@ -430,42 +421,42 @@ dependencies = [
[[package]]
name = "windows_aarch64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "41d2aa71f6f0cbe00ae5167d90ef3cfe66527d6f613ca78ac8024c3ccab9a19e"
+checksum = "8c9864e83243fdec7fc9c5444389dcbbfd258f745e7853198f365e3c4968a608"
[[package]]
name = "windows_aarch64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd0f252f5a35cac83d6311b2e795981f5ee6e67eb1f9a7f64eb4500fbc4dcdb4"
+checksum = "4c8b1b673ffc16c47a9ff48570a9d85e25d265735c503681332589af6253c6c7"
[[package]]
name = "windows_i686_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fbeae19f6716841636c28d695375df17562ca208b2b7d0dc47635a50ae6c5de7"
+checksum = "de3887528ad530ba7bdbb1faa8275ec7a1155a45ffa57c37993960277145d640"
[[package]]
name = "windows_i686_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "84c12f65daa39dd2babe6e442988fc329d6243fdce47d7d2d155b8d874862246"
+checksum = "bf4d1122317eddd6ff351aa852118a2418ad4214e6613a50e0191f7004372605"
[[package]]
name = "windows_x86_64_gnu"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "bf7b1b21b5362cbc318f686150e5bcea75ecedc74dd157d874d754a2ca44b0ed"
+checksum = "c1040f221285e17ebccbc2591ffdc2d44ee1f9186324dd3e84e99ac68d699c45"
[[package]]
name = "windows_x86_64_gnullvm"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "09d525d2ba30eeb3297665bd434a54297e4170c7f1a44cad4ef58095b4cd2028"
+checksum = "628bfdf232daa22b0d64fdb62b09fcc36bb01f05a3939e20ab73aaf9470d0463"
[[package]]
name = "windows_x86_64_msvc"
-version = "0.42.0"
+version = "0.42.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f40009d85759725a34da6d89a94e63d7bdc50a862acf0dbc7c8e488f1edcb6f5"
+checksum = "447660ad36a13288b1db4d4248e857b510e8c3a225c822ba4fb748c0aafecffd"
diff --git a/compiler/rustc_codegen_cranelift/Cargo.toml b/compiler/rustc_codegen_cranelift/Cargo.toml
index 5dadcaaec..a2890f6dd 100644
--- a/compiler/rustc_codegen_cranelift/Cargo.toml
+++ b/compiler/rustc_codegen_cranelift/Cargo.toml
@@ -15,15 +15,15 @@ crate-type = ["dylib"]
[dependencies]
# These have to be in sync with each other
-cranelift-codegen = { version = "0.93", features = ["unwind", "all-arch"] }
-cranelift-frontend = { version = "0.93" }
-cranelift-module = { version = "0.93" }
-cranelift-native = { version = "0.93" }
-cranelift-jit = { version = "0.93", optional = true }
-cranelift-object = { version = "0.93" }
+cranelift-codegen = { version = "0.95.1", features = ["unwind", "all-arch"] }
+cranelift-frontend = { version = "0.95.1" }
+cranelift-module = { version = "0.95.1" }
+cranelift-native = { version = "0.95.1" }
+cranelift-jit = { version = "0.95.1", optional = true }
+cranelift-object = { version = "0.95.1" }
target-lexicon = "0.12.0"
-gimli = { version = "0.26.0", default-features = false, features = ["write"]}
-object = { version = "0.29.0", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
+gimli = { version = "0.27.2", default-features = false, features = ["write"]}
+object = { version = "0.30.3", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] }
indexmap = "1.9.3"
libloading = { version = "0.7.3", optional = true }
diff --git a/compiler/rustc_codegen_cranelift/Readme.md b/compiler/rustc_codegen_cranelift/Readme.md
index b87a9dc51..c5222982a 100644
--- a/compiler/rustc_codegen_cranelift/Readme.md
+++ b/compiler/rustc_codegen_cranelift/Readme.md
@@ -22,10 +22,9 @@ $ ./test.sh
For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.rs`.
-Alternatively you can download a pre built version from [Github Actions]. It is listed in the artifacts section
-of workflow runs. Unfortunately due to GHA restrictions you need to be logged in to access it.
+Alternatively you can download a pre built version from the [releases] page.
-[Github Actions]: https://github.com/bjorn3/rustc_codegen_cranelift/actions?query=branch%3Amaster+event%3Apush+is%3Asuccess
+[releases]: https://github.com/bjorn3/rustc_codegen_cranelift/releases/tag/dev
## Usage
diff --git a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
index f21507629..7ddf91ad0 100644
--- a/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
+++ b/compiler/rustc_codegen_cranelift/build_sysroot/Cargo.lock
@@ -4,9 +4,9 @@ version = 3
[[package]]
name = "addr2line"
-version = "0.17.0"
+version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b9ecd88a8c8378ca913a680cd98f0f13ac67383d35993f86c90a70e3f137816b"
+checksum = "a76fd60b23679b7d19bd066031410fb7e458ccc5e958eb5c325888ce4baedc97"
dependencies = [
"compiler_builtins",
"gimli",
@@ -50,9 +50,9 @@ dependencies = [
[[package]]
name = "compiler_builtins"
-version = "0.1.89"
+version = "0.1.91"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9fc9c2080d347a2c316518840ac9194644a9993dfa1e9778ef38979a339f5d8b"
+checksum = "571298a3cce7e2afbd3d61abb91a18667d5ab25993ec577a88ee8ac45f00cc3a"
dependencies = [
"rustc-std-workspace-core",
]
@@ -95,9 +95,9 @@ dependencies = [
[[package]]
name = "gimli"
-version = "0.26.2"
+version = "0.27.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "22030e2c5a68ec659fde1e949a745124b48e6fa8b045b7ed5bd1fe4ccc5c4e5d"
+checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-alloc",
@@ -128,9 +128,9 @@ dependencies = [
[[package]]
name = "libc"
-version = "0.2.140"
+version = "0.2.142"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "99227334921fae1a979cf0bfdfcc6b3e5ce376ef57e16fb6fb3ea2ed6095f80c"
+checksum = "6a987beff54b60ffa6d51982e1aa1146bc42f19bd26be28b0586f252fccf5317"
dependencies = [
"rustc-std-workspace-core",
]
@@ -147,9 +147,9 @@ dependencies = [
[[package]]
name = "miniz_oxide"
-version = "0.5.4"
+version = "0.6.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "96590ba8f175222643a85693f33d26e9c8a015f599c216509b1a6894af675d34"
+checksum = "b275950c28b37e794e8c55d88aeb5e139d0ce23fdbbeda68f8d7174abdf9e8fa"
dependencies = [
"adler",
"compiler_builtins",
@@ -159,9 +159,9 @@ dependencies = [
[[package]]
name = "object"
-version = "0.29.0"
+version = "0.30.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "21158b2c33aa6d4561f1c0a6ea283ca92bc54802a93b263e910746d679a7eb53"
+checksum = "ea86265d3d3dcb6a27fc51bd29a4bf387fae9d2986b823079d4986af253eb439"
dependencies = [
"compiler_builtins",
"memchr",
@@ -202,9 +202,9 @@ dependencies = [
[[package]]
name = "rustc-demangle"
-version = "0.1.21"
+version = "0.1.23"
source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ef03e0a2b150c7a90d01faf6254c9c48a41e95fb2a8c2ac1c6f0d2b9aefc342"
+checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76"
dependencies = [
"compiler_builtins",
"rustc-std-workspace-core",
diff --git a/compiler/rustc_codegen_cranelift/build_system/mod.rs b/compiler/rustc_codegen_cranelift/build_system/mod.rs
index 8a53acdf7..e4ed9be23 100644
--- a/compiler/rustc_codegen_cranelift/build_system/mod.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/mod.rs
@@ -43,7 +43,7 @@ pub(crate) enum SysrootKind {
Llvm,
}
-pub fn main() {
+pub(crate) fn main() {
if env::var("RUST_BACKTRACE").is_err() {
env::set_var("RUST_BACKTRACE", "1");
}
diff --git a/compiler/rustc_codegen_cranelift/build_system/tests.rs b/compiler/rustc_codegen_cranelift/build_system/tests.rs
index 261948a69..0c25b4aad 100644
--- a/compiler/rustc_codegen_cranelift/build_system/tests.rs
+++ b/compiler/rustc_codegen_cranelift/build_system/tests.rs
@@ -2,7 +2,6 @@ use super::build_sysroot;
use super::config;
use super::path::{Dirs, RelPath};
use super::prepare::GitRepo;
-use super::rustc_info::get_host_triple;
use super::utils::{spawn_and_wait, spawn_and_wait_with_input, CargoProject, Compiler};
use super::SysrootKind;
use std::env;
@@ -102,14 +101,14 @@ pub(crate) static RAND_REPO: GitRepo =
pub(crate) static RAND: CargoProject = CargoProject::new(&RAND_REPO.source_dir(), "rand");
pub(crate) static REGEX_REPO: GitRepo =
- GitRepo::github("rust-lang", "regex", "a9b2e02352db92ce1f6e5b7ecd41b8bbffbe161a", "regex");
+ GitRepo::github("rust-lang", "regex", "32fed9429eafba0ae92a64b01796a0c5a75b88c8", "regex");
pub(crate) static REGEX: CargoProject = CargoProject::new(&REGEX_REPO.source_dir(), "regex");
pub(crate) static PORTABLE_SIMD_REPO: GitRepo = GitRepo::github(
"rust-lang",
"portable-simd",
- "9bd30e77b3a3c699af102ebb3df0f6110f8aa02e",
+ "ad8afa8c81273b3b49acbea38cd3bcf17a34cf2b",
"portable-simd",
);
@@ -186,7 +185,9 @@ const EXTENDED_SYSROOT_SUITE: &[TestCase] = &[
if runner.is_native {
let mut run_cmd = REGEX.test(&runner.target_compiler, &runner.dirs);
- run_cmd.args(["--workspace", "--", "-q"]);
+ // regex-capi and regex-debug don't have any tests. Nor do they contain any code
+ // that is useful to test with cg_clif. Skip building them to reduce test time.
+ run_cmd.args(["-p", "regex", "-p", "regex-syntax", "--", "-q"]);
spawn_and_wait(run_cmd);
} else {
eprintln!("Cross-Compiling: Not running tests");
@@ -228,8 +229,11 @@ pub(crate) fn run_tests(
target_triple.clone(),
);
- let runner =
- TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+ let runner = TestRunner::new(
+ dirs.clone(),
+ target_compiler,
+ bootstrap_host_compiler.triple == target_triple,
+ );
BUILD_EXAMPLE_OUT_DIR.ensure_fresh(dirs);
runner.run_testsuite(NO_SYSROOT_SUITE);
@@ -250,8 +254,11 @@ pub(crate) fn run_tests(
target_triple.clone(),
);
- let runner =
- TestRunner::new(dirs.clone(), target_compiler, get_host_triple() == target_triple);
+ let runner = TestRunner::new(
+ dirs.clone(),
+ target_compiler,
+ bootstrap_host_compiler.triple == target_triple,
+ );
if run_base_sysroot {
runner.run_testsuite(BASE_SYSROOT_SUITE);
@@ -275,7 +282,7 @@ struct TestRunner {
}
impl TestRunner {
- pub fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
+ fn new(dirs: Dirs, mut target_compiler: Compiler, is_native: bool) -> Self {
if let Ok(rustflags) = env::var("RUSTFLAGS") {
target_compiler.rustflags.push(' ');
target_compiler.rustflags.push_str(&rustflags);
@@ -297,7 +304,7 @@ impl TestRunner {
Self { is_native, jit_supported, dirs, target_compiler }
}
- pub fn run_testsuite(&self, tests: &[TestCase]) {
+ fn run_testsuite(&self, tests: &[TestCase]) {
for TestCase { config, cmd } in tests {
let (tag, testname) = config.split_once('.').unwrap();
let tag = tag.to_uppercase();
@@ -382,7 +389,7 @@ impl TestRunner {
spawn_and_wait(self.rustc_command(args));
}
- fn run_out_command<'a>(&self, name: &str, args: &[&str]) {
+ fn run_out_command(&self, name: &str, args: &[&str]) {
let mut full_cmd = vec![];
// Prepend the RUN_WRAPPER's
diff --git a/compiler/rustc_codegen_cranelift/example/alloc_example.rs b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
index 4ede2fe4e..d994e2fbc 100644
--- a/compiler/rustc_codegen_cranelift/example/alloc_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/alloc_example.rs
@@ -18,7 +18,7 @@ extern "C" {
}
#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
core::intrinsics::abort();
}
diff --git a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
index d270fec6b..f7edfa960 100644
--- a/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
+++ b/compiler/rustc_codegen_cranelift/example/arbitrary_self_types_pointers_and_wrappers.rs
@@ -3,8 +3,8 @@
#![feature(arbitrary_self_types, unsize, coerce_unsized, dispatch_from_dyn)]
use std::{
- ops::{Deref, CoerceUnsized, DispatchFromDyn},
marker::Unsize,
+ ops::{CoerceUnsized, Deref, DispatchFromDyn},
};
struct Ptr<T: ?Sized>(Box<T>);
@@ -33,7 +33,6 @@ impl<T: ?Sized> Deref for Wrapper<T> {
impl<T: CoerceUnsized<U>, U> CoerceUnsized<Wrapper<U>> for Wrapper<T> {}
impl<T: DispatchFromDyn<U>, U> DispatchFromDyn<Wrapper<U>> for Wrapper<T> {}
-
trait Trait {
// This method isn't object-safe yet. Unsized by-value `self` is object-safe (but not callable
// without unsized_locals), but wrappers around `Self` currently are not.
diff --git a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
index 6c338e999..22fc6ff33 100644
--- a/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
+++ b/compiler/rustc_codegen_cranelift/example/dst-field-align.rs
@@ -2,7 +2,7 @@
#![allow(dead_code)]
struct Foo<T: ?Sized> {
a: u16,
- b: T
+ b: T,
}
trait Bar {
@@ -10,58 +10,57 @@ trait Bar {
}
impl Bar for usize {
- fn get(&self) -> usize { *self }
+ fn get(&self) -> usize {
+ *self
+ }
}
struct Baz<T: ?Sized> {
- a: T
+ a: T,
}
struct HasDrop<T: ?Sized> {
ptr: Box<usize>,
- data: T
+ data: T,
}
fn main() {
// Test that zero-offset works properly
- let b : Baz<usize> = Baz { a: 7 };
+ let b: Baz<usize> = Baz { a: 7 };
assert_eq!(b.a.get(), 7);
- let b : &Baz<dyn Bar> = &b;
+ let b: &Baz<dyn Bar> = &b;
assert_eq!(b.a.get(), 7);
// Test that the field is aligned properly
- let f : Foo<usize> = Foo { a: 0, b: 11 };
+ let f: Foo<usize> = Foo { a: 0, b: 11 };
assert_eq!(f.b.get(), 11);
- let ptr1 : *const u8 = &f.b as *const _ as *const u8;
+ let ptr1: *const u8 = &f.b as *const _ as *const u8;
- let f : &Foo<dyn Bar> = &f;
- let ptr2 : *const u8 = &f.b as *const _ as *const u8;
+ let f: &Foo<dyn Bar> = &f;
+ let ptr2: *const u8 = &f.b as *const _ as *const u8;
assert_eq!(f.b.get(), 11);
// The pointers should be the same
assert_eq!(ptr1, ptr2);
// Test that nested DSTs work properly
- let f : Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 }};
+ let f: Foo<Foo<usize>> = Foo { a: 0, b: Foo { a: 1, b: 17 } };
assert_eq!(f.b.b.get(), 17);
- let f : &Foo<Foo<dyn Bar>> = &f;
+ let f: &Foo<Foo<dyn Bar>> = &f;
assert_eq!(f.b.b.get(), 17);
// Test that get the pointer via destructuring works
- let f : Foo<usize> = Foo { a: 0, b: 11 };
- let f : &Foo<dyn Bar> = &f;
+ let f: Foo<usize> = Foo { a: 0, b: 11 };
+ let f: &Foo<dyn Bar> = &f;
let &Foo { a: _, b: ref bar } = f;
assert_eq!(bar.get(), 11);
// Make sure that drop flags don't screw things up
- let d : HasDrop<Baz<[i32; 4]>> = HasDrop {
- ptr: Box::new(0),
- data: Baz { a: [1,2,3,4] }
- };
- assert_eq!([1,2,3,4], d.data.a);
+ let d: HasDrop<Baz<[i32; 4]>> = HasDrop { ptr: Box::new(0), data: Baz { a: [1, 2, 3, 4] } };
+ assert_eq!([1, 2, 3, 4], d.data.a);
- let d : &HasDrop<Baz<[i32]>> = &d;
- assert_eq!(&[1,2,3,4], &d.data.a);
+ let d: &HasDrop<Baz<[i32]>> = &d;
+ assert_eq!(&[1, 2, 3, 4], &d.data.a);
}
diff --git a/compiler/rustc_codegen_cranelift/example/example.rs b/compiler/rustc_codegen_cranelift/example/example.rs
index d5c122bf6..885e55bc7 100644
--- a/compiler/rustc_codegen_cranelift/example/example.rs
+++ b/compiler/rustc_codegen_cranelift/example/example.rs
@@ -11,11 +11,7 @@ pub fn abc(a: u8) -> u8 {
}
pub fn bcd(b: bool, a: u8) -> u8 {
- if b {
- a * 2
- } else {
- a * 3
- }
+ if b { a * 2 } else { a * 3 }
}
pub fn call() {
diff --git a/compiler/rustc_codegen_cranelift/example/issue-72793.rs b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
index b1bb9b8e1..166b00600 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-72793.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-72793.rs
@@ -2,7 +2,9 @@
#![feature(type_alias_impl_trait)]
-trait T { type Item; }
+trait T {
+ type Item;
+}
type Alias<'a> = impl T<Item = &'a ()>;
diff --git a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
index 039100696..6f39c5edc 100644
--- a/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
+++ b/compiler/rustc_codegen_cranelift/example/issue-91827-extern-types.rs
@@ -40,10 +40,7 @@ impl<T, const N: usize> ListImpl<T, N> {
}
}
-pub static A: ListImpl<u128, 3> = ListImpl {
- len: 3,
- data: [5, 6, 7],
-};
+pub static A: ListImpl<u128, 3> = ListImpl { len: 3, data: [5, 6, 7] };
pub static A_REF: &'static List<u128> = A.as_list();
pub static A_TAIL_OFFSET: isize = tail_offset(A.as_list());
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core.rs b/compiler/rustc_codegen_cranelift/example/mini_core.rs
index 73b83b89f..ea97e9f06 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core.rs
@@ -37,13 +37,13 @@ impl<T: ?Sized + Unsize<U>, U: ?Sized> CoerceUnsized<*mut U> for *mut T {}
pub trait DispatchFromDyn<T> {}
// &T -> &U
-impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a U> for &'a T {}
// &mut T -> &mut U
-impl<'a, T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
+impl<'a, T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<&'a mut U> for &'a mut T {}
// *const T -> *const U
-impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*const U> for *const T {}
// *mut T -> *mut U
-impl<T: ?Sized+Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
+impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<*mut U> for *mut T {}
impl<T: ?Sized + Unsize<U>, U: ?Sized> DispatchFromDyn<Box<U>> for Box<T> {}
#[lang = "receiver"]
@@ -288,7 +288,6 @@ impl PartialEq for u32 {
}
}
-
impl PartialEq for u64 {
fn eq(&self, other: &u64) -> bool {
(*self) == (*other)
@@ -361,7 +360,7 @@ impl<T: ?Sized> PartialEq for *const T {
}
}
-impl <T: PartialEq> PartialEq for Option<T> {
+impl<T: PartialEq> PartialEq for Option<T> {
fn eq(&self, other: &Self) -> bool {
match (self, other) {
(Some(lhs), Some(rhs)) => *lhs == *rhs,
@@ -472,7 +471,20 @@ pub fn panic(_msg: &'static str) -> ! {
#[track_caller]
fn panic_bounds_check(index: usize, len: usize) -> ! {
unsafe {
- libc::printf("index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8, len, index);
+ libc::printf(
+ "index out of bounds: the len is %d but the index is %d\n\0" as *const str as *const i8,
+ len,
+ index,
+ );
+ intrinsics::abort();
+ }
+}
+
+#[lang = "panic_cannot_unwind"]
+#[track_caller]
+fn panic_cannot_unwind() -> ! {
+ unsafe {
+ libc::puts("panic in a function that cannot unwind\n\0" as *const str as *const i8);
intrinsics::abort();
}
}
@@ -599,7 +611,7 @@ pub mod libc {
// functions. legacy_stdio_definitions.lib which provides the printf wrapper functions as normal
// symbols to link against.
#[cfg_attr(unix, link(name = "c"))]
- #[cfg_attr(target_env="msvc", link(name="legacy_stdio_definitions"))]
+ #[cfg_attr(target_env = "msvc", link(name = "legacy_stdio_definitions"))]
extern "C" {
pub fn printf(format: *const i8, ...) -> i32;
}
@@ -638,7 +650,7 @@ impl<T> Index<usize> for [T] {
}
}
-extern {
+extern "C" {
type VaListImpl;
}
@@ -648,23 +660,33 @@ pub struct VaList<'a>(&'a mut VaListImpl);
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
-pub macro stringify($($t:tt)*) { /* compiler built-in */ }
+pub macro stringify($($t:tt)*) {
+ /* compiler built-in */
+}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
-pub macro file() { /* compiler built-in */ }
+pub macro file() {
+ /* compiler built-in */
+}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
-pub macro line() { /* compiler built-in */ }
+pub macro line() {
+ /* compiler built-in */
+}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
-pub macro cfg() { /* compiler built-in */ }
+pub macro cfg() {
+ /* compiler built-in */
+}
#[rustc_builtin_macro]
#[rustc_macro_transparency = "semitransparent"]
-pub macro global_asm() { /* compiler built-in */ }
+pub macro global_asm() {
+ /* compiler built-in */
+}
pub static A_STATIC: u8 = 42;
@@ -676,7 +698,7 @@ struct PanicLocation {
}
#[no_mangle]
-#[cfg(not(windows))]
+#[cfg(not(all(windows, target_env = "gnu")))]
pub fn get_tls() -> u8 {
#[thread_local]
static A: u8 = 42;
diff --git a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
index 6ad3268e7..5a55aa215 100644
--- a/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
+++ b/compiler/rustc_codegen_cranelift/example/mini_core_hello_world.rs
@@ -319,7 +319,7 @@ fn main() {
from_decimal_string();
- #[cfg(not(any(jit, windows)))]
+ #[cfg(all(not(jit), not(all(windows, target_env = "gnu"))))]
test_tls();
#[cfg(all(not(jit), target_arch = "x86_64", any(target_os = "linux", target_os = "darwin")))]
@@ -524,6 +524,7 @@ pub enum E1 {
// Computing the discriminant used to be done using the niche type (here `u8`,
// from the `bool` field of `V1`), overflowing for variants with large enough
// indices (`V3` and `V4`), causing them to be interpreted as other variants.
+#[rustfmt::skip]
pub enum E2<X> {
V1 { f: bool },
diff --git a/compiler/rustc_codegen_cranelift/example/mod_bench.rs b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
index e3e8a3c2d..f15e48acc 100644
--- a/compiler/rustc_codegen_cranelift/example/mod_bench.rs
+++ b/compiler/rustc_codegen_cranelift/example/mod_bench.rs
@@ -3,15 +3,15 @@
#[cfg_attr(unix, link(name = "c"))]
#[cfg_attr(target_env = "msvc", link(name = "msvcrt"))]
-extern {}
+extern "C" {}
#[panic_handler]
-fn panic_handler(_: &core::panic::PanicInfo) -> ! {
+fn panic_handler(_: &core::panic::PanicInfo<'_>) -> ! {
core::intrinsics::abort();
}
-#[lang="eh_personality"]
-fn eh_personality(){}
+#[lang = "eh_personality"]
+fn eh_personality() {}
// Required for rustc_codegen_llvm
#[no_mangle]
diff --git a/compiler/rustc_codegen_cranelift/example/std_example.rs b/compiler/rustc_codegen_cranelift/example/std_example.rs
index e34b35d5c..ab4045d11 100644
--- a/compiler/rustc_codegen_cranelift/example/std_example.rs
+++ b/compiler/rustc_codegen_cranelift/example/std_example.rs
@@ -1,4 +1,4 @@
-#![feature(core_intrinsics, generators, generator_trait, is_sorted)]
+#![feature(core_intrinsics, generators, generator_trait, is_sorted, repr_simd)]
#[cfg(target_arch = "x86_64")]
use std::arch::x86_64::*;
@@ -56,7 +56,10 @@ fn main() {
assert_eq!(0b0000000000000000000000000010000010000000000000000000000000000000_0000000000100000000000000000000000001000000000000100000000000000u128.leading_zeros(), 26);
assert_eq!(0b0000000000000000000000000010000000000000000000000000000000000000_0000000000000000000000000000000000001000000000000000000010000000u128.trailing_zeros(), 7);
- assert_eq!(core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128), 170141183460469231731687303715884105727i128);
+ assert_eq!(
+ core::intrinsics::saturating_sub(0, -170141183460469231731687303715884105728i128),
+ 170141183460469231731687303715884105727i128
+ );
std::hint::black_box(std::hint::black_box(7571400400375753350092698930310845914i128) * 10);
assert!(0i128.checked_div(2i128).is_some());
@@ -113,7 +116,9 @@ fn main() {
Box::pin(move |mut _task_context| {
yield ();
- }).as_mut().resume(0);
+ })
+ .as_mut()
+ .resume(0);
#[derive(Copy, Clone)]
enum Nums {
@@ -148,12 +153,20 @@ fn main() {
enum Never {}
}
+
+ foo(I64X2(0, 0));
}
fn panic(_: u128) {
panic!();
}
+#[repr(simd)]
+struct I64X2(i64, i64);
+
+#[allow(improper_ctypes_definitions)]
+extern "C" fn foo(_a: I64X2) {}
+
#[cfg(target_arch = "x86_64")]
#[target_feature(enable = "sse2")]
unsafe fn test_simd() {
@@ -168,7 +181,10 @@ unsafe fn test_simd() {
let (zero0, zero1) = std::mem::transmute::<_, (u64, u64)>(x);
assert_eq!((zero0, zero1), (0, 0));
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
- assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
+ assert_eq!(
+ std::mem::transmute::<_, [u16; 8]>(cmp_eq),
+ [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]
+ );
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
test_mm_slli_si128();
@@ -182,6 +198,7 @@ unsafe fn test_simd() {
test_mm_extract_epi8();
test_mm_insert_epi16();
+ #[rustfmt::skip]
let mask1 = _mm_movemask_epi8(dbg!(_mm_setr_epi8(255u8 as i8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)));
assert_eq!(mask1, 1);
}
@@ -343,7 +360,7 @@ fn test_checked_mul() {
#[derive(PartialEq)]
enum LoopState {
Continue(()),
- Break(())
+ Break(()),
}
pub enum Instruction {
diff --git a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
index 2cb84786f..3c8789166 100644
--- a/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
+++ b/compiler/rustc_codegen_cranelift/example/subslice-patterns-const-eval.rs
@@ -19,7 +19,9 @@ macro_rules! n {
// This macro has an unused variable so that it can be repeated base on the
// number of times a repeated variable (`$e` in `z`) occurs.
macro_rules! zed {
- ($e:expr) => { Z }
+ ($e:expr) => {
+ Z
+ };
}
macro_rules! z {
@@ -32,12 +34,14 @@ macro_rules! z {
macro_rules! compare_evaluation {
($e:expr, $t:ty $(,)?) => {{
const CONST_EVAL: $t = $e;
- const fn const_eval() -> $t { $e }
+ const fn const_eval() -> $t {
+ $e
+ }
static CONST_EVAL2: $t = const_eval();
let runtime_eval = $e;
assert_eq!(CONST_EVAL, runtime_eval);
assert_eq!(CONST_EVAL2, runtime_eval);
- }}
+ }};
}
// Repeat `$test`, substituting the given macro variables with the given
@@ -65,6 +69,7 @@ macro_rules! repeat {
}
}
+#[rustfmt::skip]
fn main() {
repeat! {
($arr $Ty); n, N; z, Z:
diff --git a/compiler/rustc_codegen_cranelift/rust-toolchain b/compiler/rustc_codegen_cranelift/rust-toolchain
index 2236a6ca1..59ad80c32 100644
--- a/compiler/rustc_codegen_cranelift/rust-toolchain
+++ b/compiler/rustc_codegen_cranelift/rust-toolchain
@@ -1,3 +1,3 @@
[toolchain]
-channel = "nightly-2023-03-15"
+channel = "nightly-2023-04-29"
components = ["rust-src", "rustc-dev", "llvm-tools-preview"]
diff --git a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
index 939a1f1ca..e2db7d03a 100644
--- a/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/cargo-clif.rs
@@ -64,7 +64,7 @@ fn main() {
};
#[cfg(unix)]
- Command::new("cargo").args(args).exec();
+ panic!("Failed to spawn cargo: {}", Command::new("cargo").args(args).exec());
#[cfg(not(unix))]
std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
index b9bba7f2e..ab496a4a6 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustc-clif.rs
@@ -15,22 +15,24 @@ fn main() {
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
);
- let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ let passed_args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ let mut args = vec![];
args.push(OsString::from("-Cpanic=abort"));
args.push(OsString::from("-Zpanic-abort-tests"));
let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
codegen_backend_arg.push(cg_clif_dylib_path);
args.push(codegen_backend_arg);
- if !args.contains(&OsString::from("--sysroot")) {
+ if !passed_args.contains(&OsString::from("--sysroot")) {
args.push(OsString::from("--sysroot"));
args.push(OsString::from(sysroot.to_str().unwrap()));
}
+ args.extend(passed_args);
// Ensure that the right toolchain is used
env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
#[cfg(unix)]
- Command::new("rustc").args(args).exec();
+ panic!("Failed to spawn rustc: {}", Command::new("rustc").args(args).exec());
#[cfg(not(unix))]
std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
index 167631eaf..545844446 100644
--- a/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
+++ b/compiler/rustc_codegen_cranelift/scripts/rustdoc-clif.rs
@@ -15,22 +15,24 @@ fn main() {
env::consts::DLL_PREFIX.to_string() + "rustc_codegen_cranelift" + env::consts::DLL_SUFFIX,
);
- let mut args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ let passed_args = std::env::args_os().skip(1).collect::<Vec<_>>();
+ let mut args = vec![];
args.push(OsString::from("-Cpanic=abort"));
args.push(OsString::from("-Zpanic-abort-tests"));
let mut codegen_backend_arg = OsString::from("-Zcodegen-backend=");
codegen_backend_arg.push(cg_clif_dylib_path);
args.push(codegen_backend_arg);
- if !args.contains(&OsString::from("--sysroot")) {
+ if !passed_args.contains(&OsString::from("--sysroot")) {
args.push(OsString::from("--sysroot"));
args.push(OsString::from(sysroot.to_str().unwrap()));
}
+ args.extend(passed_args);
// Ensure that the right toolchain is used
env::set_var("RUSTUP_TOOLCHAIN", env!("TOOLCHAIN_NAME"));
#[cfg(unix)]
- Command::new("rustdoc").args(args).exec();
+ panic!("Failed to spawn rustdoc: {}", Command::new("rustdoc").args(args).exec());
#[cfg(not(unix))]
std::process::exit(
diff --git a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
index 20dcb4cf3..1329d3ea0 100755
--- a/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
+++ b/compiler/rustc_codegen_cranelift/scripts/test_rustc_tests.sh
@@ -10,7 +10,8 @@ pushd rust
command -v rg >/dev/null 2>&1 || cargo install ripgrep
-rm -r tests/ui/{extern/,unsized-locals/,lto/,linkage*} || true
+# FIXME add needs-asm-support to all tests in tests/ui/asm
+rm -r tests/ui/{unsized-locals/,lto/,linkage*} || true
for test in $(rg --files-with-matches "lto|// needs-asm-support|// needs-unwind" tests/{codegen-units,ui,incremental}); do
rm $test
done
@@ -27,13 +28,24 @@ rm tests/ui/parser/unclosed-delimiter-in-dep.rs # submodule contains //~ERROR
# ================
# requires stack unwinding
+# FIXME add needs-unwind to these tests
rm tests/incremental/change_crate_dep_kind.rs
rm tests/incremental/issue-80691-bad-eval-cache.rs # -Cpanic=abort causes abort instead of exit(101)
+rm -r tests/run-make/c-unwind-abi-catch-lib-panic
+rm -r tests/run-make/c-unwind-abi-catch-panic
+rm -r tests/run-make/debug-assertions
+rm -r tests/run-make/foreign-double-unwind
+rm -r tests/run-make/foreign-exceptions
+rm -r tests/run-make/foreign-rust-exceptions
+rm -r tests/run-make/libtest-json
+rm -r tests/run-make/static-unwinding
# requires compiling with -Cpanic=unwind
rm -r tests/ui/macros/rfc-2011-nicer-assert-messages/
rm -r tests/run-make/test-benches
rm tests/ui/test-attrs/test-type.rs
+rm -r tests/run-make/const_fn_mir
+rm -r tests/run-make/intrinsic-unreachable
# vendor intrinsics
rm tests/ui/sse2.rs # cpuid not supported, so sse2 not detected
@@ -49,6 +61,7 @@ rm tests/incremental/hashes/statics.rs # same
# variadic arguments
rm tests/ui/abi/mir/mir_codegen_calls_variadic.rs # requires float varargs
rm tests/ui/abi/variadic-ffi.rs # requires callee side vararg support
+rm -r tests/run-make/c-link-to-rust-va-list-fn # requires callee side vararg support
# unsized locals
rm -r tests/run-pass-valgrind/unsized-locals
@@ -59,6 +72,19 @@ rm tests/ui/target-feature/missing-plusminus.rs # error not implemented
rm tests/ui/fn/dyn-fn-alignment.rs # wants a 256 byte alignment
rm -r tests/run-make/emit-named-files # requires full --emit support
rm -r tests/run-make/repr128-dwarf # debuginfo test
+rm -r tests/run-make/split-debuginfo # same
+rm -r tests/run-make/symbols-include-type-name # --emit=asm not supported
+rm -r tests/run-make/target-specs # i686 not supported by Cranelift
+rm -r tests/run-make/mismatching-target-triples # same
+rm -r tests/run-make/use-extern-for-plugins # same
+
+# requires LTO
+rm -r tests/run-make/cdylib
+rm -r tests/run-make/issue-14500
+rm -r tests/run-make/issue-64153
+rm -r tests/run-make/codegen-options-parsing
+rm -r tests/run-make/lto-*
+rm -r tests/run-make/reproducible-build-2
# optimization tests
# ==================
@@ -70,7 +96,14 @@ rm -r tests/run-make/fmt-write-bloat/ # tests an optimization
# backend specific tests
# ======================
rm tests/incremental/thinlto/cgu_invalidated_when_import_{added,removed}.rs # requires LLVM
+rm -r tests/run-make/cross-lang-lto # same
+rm -r tests/run-make/issue-7349 # same
+rm -r tests/run-make/sepcomp-inlining # same
+rm -r tests/run-make/sepcomp-separate # same
+rm -r tests/run-make/sepcomp-cci-copies # same
+rm -r tests/run-make/volatile-intrinsics # same
rm tests/ui/abi/stack-protector.rs # requires stack protector support
+rm -r tests/run-make/emit-stack-sizes # requires support for -Z emit-stack-sizes
# giving different but possibly correct results
# =============================================
@@ -95,13 +128,12 @@ rm tests/ui/proc-macro/no-missing-docs.rs # same
rm tests/ui/rust-2018/proc-macro-crate-in-paths.rs # same
rm tests/ui/proc-macro/allowed-signatures.rs # same
+# rustdoc-clif passes extra args, suppressing the help message when no args are passed
+rm -r tests/run-make/issue-88756-default-output
+
# doesn't work due to the way the rustc test suite is invoked.
# should work when using ./x.py test the way it is intended
# ============================================================
-rm -r tests/run-make/emit-shared-files # requires the rustdoc executable in dist/bin/
-rm -r tests/run-make/unstable-flag-required # same
-rm -r tests/run-make/rustdoc-* # same
-rm -r tests/run-make/issue-88756-default-output # same
rm -r tests/run-make/remap-path-prefix-dwarf # requires llvm-dwarfdump
rm -r tests/ui/consts/missing_span_in_backtrace.rs # expects sysroot source to be elsewhere
@@ -112,17 +144,41 @@ rm tests/incremental/spike-neg2.rs # same
rm tests/ui/simd/intrinsic/generic-reduction-pass.rs # simd_reduce_add_unordered doesn't accept an accumulator for integer vectors
-rm tests/ui/simd/intrinsic/generic-as.rs # crash when accessing vector type field (#1318)
rm tests/ui/simd/simd-bitmask.rs # crash
+rm -r tests/run-make/issue-51671 # wrong filename given in case of --emit=obj
+rm -r tests/run-make/issue-30063 # same
+rm -r tests/run-make/multiple-emits # same
+rm -r tests/run-make/output-type-permutations # same
+rm -r tests/run-make/used # same
+
# bugs in the test suite
# ======================
rm tests/ui/backtrace.rs # TODO warning
-rm tests/ui/simple_global_asm.rs # TODO add needs-asm-support
rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue
rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd
+cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist
+
+# prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by
+# rustdoc-clif
+cat <<EOF | git apply -
+diff --git a/tests/run-make/tools.mk b/tests/run-make/tools.mk
+index ea06b620c4c..b969d0009c6 100644
+--- a/tests/run-make/tools.mk
++++ b/tests/run-make/tools.mk
+@@ -9,7 +9,7 @@ RUSTC_ORIGINAL := \$(RUSTC)
+ BARE_RUSTC := \$(HOST_RPATH_ENV) '\$(RUSTC)'
+ BARE_RUSTDOC := \$(HOST_RPATH_ENV) '\$(RUSTDOC)'
+ RUSTC := \$(BARE_RUSTC) --out-dir \$(TMPDIR) -L \$(TMPDIR) \$(RUSTFLAGS)
+-RUSTDOC := \$(BARE_RUSTDOC) -L \$(TARGET_RPATH_DIR)
++RUSTDOC := \$(BARE_RUSTDOC)
+ ifdef RUSTC_LINKER
+ RUSTC := \$(RUSTC) -Clinker='\$(RUSTC_LINKER)'
+ RUSTDOC := \$(RUSTDOC) -Clinker='\$(RUSTC_LINKER)'
+EOF
+
echo "[TEST] rustc test suite"
-RUST_TEST_NOCAPTURE=1 COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
+COMPILETEST_FORCE_STAGE0=1 ./x.py test --stage 0 --test-args=--nocapture tests/{codegen-units,run-make,run-pass-valgrind,ui,incremental}
popd
diff --git a/compiler/rustc_codegen_cranelift/src/abi/comments.rs b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
index abf63e33c..364503fd3 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/comments.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/comments.rs
@@ -6,8 +6,6 @@ use std::borrow::Cow;
use rustc_middle::mir;
use rustc_target::abi::call::PassMode;
-use cranelift_codegen::entity::EntityRef;
-
use crate::prelude::*;
pub(super) fn add_args_header_comment(fx: &mut FunctionCx<'_, '_, '_>) {
@@ -91,35 +89,7 @@ pub(super) fn add_local_place_comments<'tcx>(
largest_niche: _,
} = layout.0.0;
- let (kind, extra) = match *place.inner() {
- CPlaceInner::Var(place_local, var) => {
- assert_eq!(local, place_local);
- ("ssa", Cow::Owned(format!(",var={}", var.index())))
- }
- CPlaceInner::VarPair(place_local, var1, var2) => {
- assert_eq!(local, place_local);
- ("ssa", Cow::Owned(format!("var=({}, {})", var1.index(), var2.index())))
- }
- CPlaceInner::VarLane(_local, _var, _lane) => unreachable!(),
- CPlaceInner::Addr(ptr, meta) => {
- let meta = if let Some(meta) = meta {
- Cow::Owned(format!("meta={}", meta))
- } else {
- Cow::Borrowed("")
- };
- match ptr.debug_base_and_offset() {
- (crate::pointer::PointerBase::Addr(addr), offset) => {
- ("reuse", format!("storage={}{}{}", addr, offset, meta).into())
- }
- (crate::pointer::PointerBase::Stack(stack_slot), offset) => {
- ("stack", format!("storage={}{}{}", stack_slot, offset, meta).into())
- }
- (crate::pointer::PointerBase::Dangling(align), offset) => {
- ("zst", format!("align={},offset={}", align.bytes(), offset).into())
- }
- }
- }
- };
+ let (kind, extra) = place.debug_comment();
fx.add_global_comment(format!(
"{:<5} {:5} {:30} {:4}b {}, {}{}{}",
diff --git a/compiler/rustc_codegen_cranelift/src/abi/mod.rs b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
index 91c085d3d..84e09cf0a 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/mod.rs
@@ -70,7 +70,7 @@ pub(crate) fn get_function_sig<'tcx>(
default_call_conv: CallConv,
inst: Instance<'tcx>,
) -> Signature {
- assert!(!inst.substs.needs_infer());
+ assert!(!inst.substs.has_infer());
clif_sig_from_fn_abi(
tcx,
default_call_conv,
@@ -88,10 +88,10 @@ pub(crate) fn import_function<'tcx>(
let sig = get_function_sig(tcx, module.target_config().default_call_conv, inst);
match module.declare_function(name, Linkage::Import, &sig) {
Ok(func_id) => func_id,
- Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
"attempt to declare `{name}` as function, but it was already declared as static"
)),
- Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(&format!(
+ Err(ModuleError::IncompatibleSignature(_, prev_sig, new_sig)) => tcx.sess.fatal(format!(
"attempt to declare `{name}` with signature {new_sig:?}, \
but it was already declared with signature {prev_sig:?}"
)),
@@ -432,11 +432,9 @@ pub(crate) fn codegen_terminator_call<'tcx>(
let is_cold = if fn_sig.abi() == Abi::RustCold {
true
} else {
- instance
- .map(|inst| {
- fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
- })
- .unwrap_or(false)
+ instance.is_some_and(|inst| {
+ fx.tcx.codegen_fn_attrs(inst.def_id()).flags.contains(CodegenFnAttrFlags::COLD)
+ })
};
if is_cold {
fx.bcx.set_cold_block(fx.bcx.current_block().unwrap());
@@ -470,7 +468,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
};
// Pass the caller location for `#[track_caller]`.
- if instance.map(|inst| inst.def.requires_caller_location(fx.tcx)).unwrap_or(false) {
+ if instance.is_some_and(|inst| inst.def.requires_caller_location(fx.tcx)) {
let caller_location = fx.get_caller_location(source_info);
args.push(CallArgument { value: caller_location, is_owned: false });
}
@@ -548,7 +546,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
if !matches!(fn_sig.abi(), Abi::C { .. }) {
fx.tcx.sess.span_fatal(
source_info.span,
- &format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
+ format!("Variadic call for non-C abi {:?}", fn_sig.abi()),
);
}
let sig_ref = fx.bcx.func.dfg.call_signature(call_inst).unwrap();
@@ -560,7 +558,7 @@ pub(crate) fn codegen_terminator_call<'tcx>(
// FIXME set %al to upperbound on float args once floats are supported
fx.tcx.sess.span_fatal(
source_info.span,
- &format!("Non int ty {:?} for variadic call", ty),
+ format!("Non int ty {:?} for variadic call", ty),
);
}
AbiParam::new(ty)
@@ -605,9 +603,9 @@ pub(crate) fn codegen_drop<'tcx>(
// | ... |
// \-------/
//
- let (ptr, vtable) = drop_place.to_ptr_maybe_unsized();
+ let (ptr, vtable) = drop_place.to_ptr_unsized();
let ptr = ptr.get_addr(fx);
- let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable.unwrap());
+ let drop_fn = crate::vtable::drop_fn_of_obj(fx, vtable);
// FIXME(eddyb) perhaps move some of this logic into
// `Instance::resolve_drop_in_place`?
diff --git a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
index e5ad31eb9..d847e524f 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/pass_mode.rs
@@ -84,7 +84,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
attrs
)],
Abi::Vector { .. } => {
- let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+ let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
smallvec![AbiParam::new(vector_ty)]
}
_ => unreachable!("{:?}", self.layout.abi),
@@ -135,7 +135,7 @@ impl<'tcx> ArgAbiExt<'tcx> for ArgAbi<'tcx, Ty<'tcx>> {
(None, vec![AbiParam::new(scalar_to_clif_type(tcx, scalar))])
}
Abi::Vector { .. } => {
- let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout).unwrap();
+ let vector_ty = crate::intrinsics::clif_vector_type(tcx, self.layout);
(None, vec![AbiParam::new(vector_ty)])
}
_ => unreachable!("{:?}", self.layout.abi),
diff --git a/compiler/rustc_codegen_cranelift/src/abi/returning.rs b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
index 6d3e8eda2..14e54d5ee 100644
--- a/compiler/rustc_codegen_cranelift/src/abi/returning.rs
+++ b/compiler/rustc_codegen_cranelift/src/abi/returning.rs
@@ -9,7 +9,7 @@ use smallvec::{smallvec, SmallVec};
/// this adds an extra parameter pointing to where the return value needs to be stored.
pub(super) fn codegen_return_param<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
- ssa_analyzed: &rustc_index::vec::IndexVec<Local, crate::analyze::SsaKind>,
+ ssa_analyzed: &rustc_index::IndexSlice<Local, crate::analyze::SsaKind>,
block_params_iter: &mut impl Iterator<Item = Value>,
) -> CPlace<'tcx> {
let (ret_place, ret_param): (_, SmallVec<[_; 2]>) = match fx.fn_abi.as_ref().unwrap().ret.mode {
@@ -63,11 +63,11 @@ pub(super) fn codegen_with_call_return_arg<'tcx>(
let (ret_temp_place, return_ptr) = match ret_arg_abi.mode {
PassMode::Ignore => (None, None),
PassMode::Indirect { attrs: _, extra_attrs: None, on_stack: _ } => {
- if matches!(ret_place.inner(), CPlaceInner::Addr(_, None)) {
+ if let Some(ret_ptr) = ret_place.try_to_ptr() {
// This is an optimization to prevent unnecessary copies of the return value when
// the return place is already a memory place as opposed to a register.
// This match arm can be safely removed.
- (None, Some(ret_place.to_ptr().get_addr(fx)))
+ (None, Some(ret_ptr.get_addr(fx)))
} else {
let place = CPlace::new_stack_slot(fx, ret_arg_abi.layout);
(Some(place), Some(place.to_ptr().get_addr(fx)))
diff --git a/compiler/rustc_codegen_cranelift/src/allocator.rs b/compiler/rustc_codegen_cranelift/src/allocator.rs
index 2c246ceb3..d4b1ae2b6 100644
--- a/compiler/rustc_codegen_cranelift/src/allocator.rs
+++ b/compiler/rustc_codegen_cranelift/src/allocator.rs
@@ -3,10 +3,12 @@
use crate::prelude::*;
-use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_ast::expand::allocator::{
+ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
+ ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
+};
use rustc_codegen_ssa::base::allocator_kind_for_codegen;
use rustc_session::config::OomStrategy;
-use rustc_span::symbol::sym;
/// Returns whether an allocator shim was created
pub(crate) fn codegen(
@@ -34,41 +36,43 @@ fn codegen_inner(
) {
let usize_ty = module.target_config().pointer_type();
- for method in ALLOCATOR_METHODS {
- let mut arg_tys = Vec::with_capacity(method.inputs.len());
- for ty in method.inputs.iter() {
- match *ty {
- AllocatorTy::Layout => {
- arg_tys.push(usize_ty); // size
- arg_tys.push(usize_ty); // align
- }
- AllocatorTy::Ptr => arg_tys.push(usize_ty),
- AllocatorTy::Usize => arg_tys.push(usize_ty),
+ if kind == AllocatorKind::Default {
+ for method in ALLOCATOR_METHODS {
+ let mut arg_tys = Vec::with_capacity(method.inputs.len());
+ for ty in method.inputs.iter() {
+ match *ty {
+ AllocatorTy::Layout => {
+ arg_tys.push(usize_ty); // size
+ arg_tys.push(usize_ty); // align
+ }
+ AllocatorTy::Ptr => arg_tys.push(usize_ty),
+ AllocatorTy::Usize => arg_tys.push(usize_ty),
- AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
+ }
}
- }
- let output = match method.output {
- AllocatorTy::ResultPtr => Some(usize_ty),
- AllocatorTy::Unit => None,
+ let output = match method.output {
+ AllocatorTy::ResultPtr => Some(usize_ty),
+ AllocatorTy::Unit => None,
- AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
- panic!("invalid allocator output")
- }
- };
+ AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+ panic!("invalid allocator output")
+ }
+ };
- let sig = Signature {
- call_conv: module.target_config().default_call_conv,
- params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
- returns: output.into_iter().map(AbiParam::new).collect(),
- };
- crate::common::create_wrapper_function(
- module,
- unwind_context,
- sig,
- &format!("__rust_{}", method.name),
- &kind.fn_name(method.name),
- );
+ let sig = Signature {
+ call_conv: module.target_config().default_call_conv,
+ params: arg_tys.iter().cloned().map(AbiParam::new).collect(),
+ returns: output.into_iter().map(AbiParam::new).collect(),
+ };
+ crate::common::create_wrapper_function(
+ module,
+ unwind_context,
+ sig,
+ &global_fn_name(method.name),
+ &default_fn_name(method.name),
+ );
+ }
}
let sig = Signature {
@@ -81,7 +85,7 @@ fn codegen_inner(
unwind_context,
sig,
"__rust_alloc_error_handler",
- &alloc_error_handler_kind.fn_name(sym::oom),
+ &alloc_error_handler_name(alloc_error_handler_kind),
);
let data_id = module.declare_data(OomStrategy::SYMBOL, Linkage::Export, false, false).unwrap();
@@ -90,4 +94,11 @@ fn codegen_inner(
let val = oom_strategy.should_panic();
data_ctx.define(Box::new([val]));
module.define_data(data_id, &data_ctx).unwrap();
+
+ let data_id =
+ module.declare_data(NO_ALLOC_SHIM_IS_UNSTABLE, Linkage::Export, false, false).unwrap();
+ let mut data_ctx = DataContext::new();
+ data_ctx.set_align(1);
+ data_ctx.define(Box::new([0]));
+ module.define_data(data_id, &data_ctx).unwrap();
}
diff --git a/compiler/rustc_codegen_cranelift/src/analyze.rs b/compiler/rustc_codegen_cranelift/src/analyze.rs
index 54d5c1c2a..359d581c1 100644
--- a/compiler/rustc_codegen_cranelift/src/analyze.rs
+++ b/compiler/rustc_codegen_cranelift/src/analyze.rs
@@ -2,7 +2,7 @@
use crate::prelude::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::StatementKind::*;
use rustc_middle::ty::Ty;
diff --git a/compiler/rustc_codegen_cranelift/src/base.rs b/compiler/rustc_codegen_cranelift/src/base.rs
index f5301f9f7..fcfa0b862 100644
--- a/compiler/rustc_codegen_cranelift/src/base.rs
+++ b/compiler/rustc_codegen_cranelift/src/base.rs
@@ -1,7 +1,7 @@
//! Codegen of a single function
use rustc_ast::InlineAsmOptions;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::layout::FnAbiOf;
use rustc_middle::ty::print::with_no_trimmed_paths;
@@ -28,7 +28,7 @@ pub(crate) fn codegen_fn<'tcx>(
module: &mut dyn Module,
instance: Instance<'tcx>,
) -> CodegenedFunction {
- debug_assert!(!instance.substs.needs_infer());
+ debug_assert!(!instance.substs.has_infer());
let symbol_name = tcx.symbol_name(instance).name.to_string();
let _timer = tcx.prof.generic_activity_with_arg("codegen fn", &*symbol_name);
@@ -141,16 +141,6 @@ pub(crate) fn compile_fn(
context.clear();
context.func = codegened_func.func;
- // If the return block is not reachable, then the SSA builder may have inserted an `iconst.i128`
- // instruction, which doesn't have an encoding.
- context.compute_cfg();
- context.compute_domtree();
- context.eliminate_unreachable_code(module.isa()).unwrap();
- context.dce(module.isa()).unwrap();
- // Some Cranelift optimizations expect the domtree to not yet be computed and as such don't
- // invalidate it when it would change.
- context.domtree.clear();
-
#[cfg(any())] // This is never true
let _clif_guard = {
use std::fmt::Write;
@@ -182,27 +172,6 @@ pub(crate) fn compile_fn(
cx.profiler.generic_activity("define function").run(|| {
context.want_disasm = cx.should_write_ir;
module.define_function(codegened_func.func_id, context).unwrap();
-
- if cx.profiler.enabled() {
- let mut recording_args = false;
- cx.profiler
- .generic_activity_with_arg_recorder(
- "define function (clif pass timings)",
- |recorder| {
- let pass_times = cranelift_codegen::timing::take_current();
- // Replace newlines with | as measureme doesn't allow control characters like
- // newlines inside strings.
- recorder.record_arg(format!("{}", pass_times).replace('\n', " | "));
- recording_args = true;
- },
- )
- .run(|| {
- if recording_args {
- // Wait a tiny bit to ensure chrome's profiler doesn't hide the event
- std::thread::sleep(std::time::Duration::from_nanos(2))
- }
- });
- }
});
if cx.should_write_ir {
@@ -216,7 +185,7 @@ pub(crate) fn compile_fn(
&clif_comments,
);
- if let Some(disasm) = &context.compiled_code().unwrap().disasm {
+ if let Some(disasm) = &context.compiled_code().unwrap().vcode {
crate::pretty_clif::write_ir_file(
&cx.output_filenames,
&format!("{}.vcode", codegened_func.symbol_name),
@@ -251,13 +220,13 @@ pub(crate) fn verify_func(
match cranelift_codegen::verify_function(&func, &flags) {
Ok(_) => {}
Err(err) => {
- tcx.sess.err(&format!("{:?}", err));
+ tcx.sess.err(format!("{:?}", err));
let pretty_error = cranelift_codegen::print_errors::pretty_verifier_error(
&func,
Some(Box::new(writer)),
err,
);
- tcx.sess.fatal(&format!("cranelift verify error:\n{}", pretty_error));
+ tcx.sess.fatal(format!("cranelift verify error:\n{}", pretty_error));
}
}
});
@@ -366,7 +335,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
fx.bcx.switch_to_block(failure);
fx.bcx.ins().nop();
- match msg {
+ match &**msg {
AssertKind::BoundsCheck { ref len, ref index } => {
let len = codegen_operand(fx, len).load_scalar(fx);
let index = codegen_operand(fx, index).load_scalar(fx);
@@ -504,7 +473,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) {
| TerminatorKind::GeneratorDrop => {
bug!("shouldn't exist at codegen {:?}", bb_data.terminator());
}
- TerminatorKind::Drop { place, target, unwind: _ } => {
+ TerminatorKind::Drop { place, target, unwind: _, replace: _ } => {
let drop_place = codegen_place(fx, *place);
crate::abi::codegen_drop(fx, source_info, drop_place);
@@ -524,13 +493,14 @@ fn codegen_stmt<'tcx>(
fx.set_debug_loc(stmt.source_info);
- #[cfg(any())] // This is never true
match &stmt.kind {
StatementKind::StorageLive(..) | StatementKind::StorageDead(..) => {} // Those are not very useful
_ => {
if fx.clif_comments.enabled() {
let inst = fx.bcx.func.layout.last_inst(cur_block).unwrap();
- fx.add_comment(inst, format!("{:?}", stmt));
+ with_no_trimmed_paths!({
+ fx.add_comment(inst, format!("{:?}", stmt));
+ });
}
}
}
@@ -660,11 +630,11 @@ fn codegen_stmt<'tcx>(
let to_ty = fx.monomorphize(to_ty);
fn is_fat_ptr<'tcx>(fx: &FunctionCx<'_, '_, 'tcx>, ty: Ty<'tcx>) -> bool {
- ty.builtin_deref(true)
- .map(|ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
+ ty.builtin_deref(true).is_some_and(
+ |ty::TypeAndMut { ty: pointee_ty, mutbl: _ }| {
has_ptr_meta(fx.tcx, pointee_ty)
- })
- .unwrap_or(false)
+ },
+ )
}
if is_fat_ptr(fx, from_ty) {
@@ -715,11 +685,11 @@ fn codegen_stmt<'tcx>(
}
Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
- operand.unsize_value(fx, lval);
+ crate::unsize::coerce_unsized_into(fx, operand, lval);
}
Rvalue::Cast(CastKind::DynStar, ref operand, _) => {
let operand = codegen_operand(fx, operand);
- operand.coerce_dyn_star(fx, lval);
+ crate::unsize::coerce_dyn_star(fx, operand, lval);
}
Rvalue::Cast(CastKind::Transmute, ref operand, _to_ty) => {
let operand = codegen_operand(fx, operand);
@@ -781,14 +751,20 @@ fn codegen_stmt<'tcx>(
let operand = operand.load_scalar(fx);
lval.write_cvalue(fx, CValue::by_val(operand, box_layout));
}
- Rvalue::NullaryOp(null_op, ty) => {
+ Rvalue::NullaryOp(ref null_op, ty) => {
assert!(lval.layout().ty.is_sized(fx.tcx, ParamEnv::reveal_all()));
let layout = fx.layout_of(fx.monomorphize(ty));
let val = match null_op {
NullOp::SizeOf => layout.size.bytes(),
NullOp::AlignOf => layout.align.abi.bytes(),
+ NullOp::OffsetOf(fields) => {
+ layout.offset_of_subfield(fx, fields.iter().map(|f| f.index())).bytes()
+ }
};
- let val = CValue::const_val(fx, fx.layout_of(fx.tcx.types.usize), val.into());
+ let val = CValue::by_val(
+ fx.bcx.ins().iconst(fx.pointer_type, i64::try_from(val).unwrap()),
+ fx.layout_of(fx.tcx.types.usize),
+ );
lval.write_cvalue(fx, val);
}
Rvalue::Aggregate(ref kind, ref operands) => {
@@ -863,9 +839,7 @@ fn codegen_array_len<'tcx>(fx: &mut FunctionCx<'_, '_, 'tcx>, place: CPlace<'tcx
let len = fx.monomorphize(len).eval_target_usize(fx.tcx, ParamEnv::reveal_all()) as i64;
fx.bcx.ins().iconst(fx.pointer_type, len)
}
- ty::Slice(_elem_ty) => {
- place.to_ptr_maybe_unsized().1.expect("Length metadata for slice place")
- }
+ ty::Slice(_elem_ty) => place.to_ptr_unsized().1,
_ => bug!("Rvalue::Len({:?})", place),
}
}
@@ -919,8 +893,7 @@ pub(crate) fn codegen_place<'tcx>(
ty::Slice(elem_ty) => {
assert!(from_end, "slice subslices should be `from_end`");
let elem_layout = fx.layout_of(*elem_ty);
- let (ptr, len) = cplace.to_ptr_maybe_unsized();
- let len = len.unwrap();
+ let (ptr, len) = cplace.to_ptr_unsized();
cplace = CPlace::for_ptr_with_extra(
ptr.offset_i64(fx, elem_layout.size.bytes() as i64 * (from as i64)),
fx.bcx.ins().iadd_imm(len, -(from as i64 + to as i64)),
@@ -993,11 +966,7 @@ fn codegen_panic_inner<'tcx>(
args: &[Value],
span: Span,
) {
- let def_id = fx
- .tcx
- .lang_items()
- .require(lang_item)
- .unwrap_or_else(|e| fx.tcx.sess.span_fatal(span, e.to_string()));
+ let def_id = fx.tcx.require_lang_item(lang_item, Some(span));
let instance = Instance::mono(fx.tcx, def_id).polymorphize(fx.tcx);
let symbol_name = fx.tcx.symbol_name(instance).name;
diff --git a/compiler/rustc_codegen_cranelift/src/cast.rs b/compiler/rustc_codegen_cranelift/src/cast.rs
index 032d11510..6bf3a866b 100644
--- a/compiler/rustc_codegen_cranelift/src/cast.rs
+++ b/compiler/rustc_codegen_cranelift/src/cast.rs
@@ -103,7 +103,7 @@ pub(crate) fn clif_int_or_float_cast(
vec![AbiParam::new(types::I64X2)],
&[from],
)[0];
- // FIXME use bitcast instead of store to get from i64x2 to i128
+ // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
size: 16,
diff --git a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
index f674ce776..f751d8c17 100644
--- a/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
+++ b/compiler/rustc_codegen_cranelift/src/codegen_i128.rs
@@ -7,7 +7,6 @@ use crate::prelude::*;
pub(crate) fn maybe_codegen<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
bin_op: BinOp,
- checked: bool,
lhs: CValue<'tcx>,
rhs: CValue<'tcx>,
) -> Option<CValue<'tcx>> {
@@ -22,69 +21,23 @@ pub(crate) fn maybe_codegen<'tcx>(
let is_signed = type_sign(lhs.layout().ty);
match bin_op {
- BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => {
- assert!(!checked);
- None
- }
- BinOp::Add | BinOp::Sub if !checked => None,
- BinOp::Mul if !checked || is_signed => {
- if !checked {
- let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let ret_val = fx.lib_call(
- "__multi3",
- vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
- vec![AbiParam::new(types::I128)],
- &args,
- )[0];
- Some(CValue::by_val(
- ret_val,
- fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
- ))
- } else {
- let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
- let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
- let lhs = lhs.load_scalar(fx);
- let rhs = rhs.load_scalar(fx);
- let oflow_ptr = oflow.to_ptr().get_addr(fx);
- let res = fx.lib_call_unadjusted(
- "__muloti4",
- vec![
- AbiParam::new(types::I128),
- AbiParam::new(types::I128),
- AbiParam::new(fx.pointer_type),
- ],
- vec![AbiParam::new(types::I128)],
- &[lhs, rhs, oflow_ptr],
- )[0];
- let oflow = oflow.to_cvalue(fx).load_scalar(fx);
- let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
- Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
- }
- }
- BinOp::Add | BinOp::Sub | BinOp::Mul => {
- assert!(checked);
- let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
- let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
- let param_types = vec![
- AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
- AbiParam::new(types::I128),
- AbiParam::new(types::I128),
- ];
- let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
- let name = match (bin_op, is_signed) {
- (BinOp::Add, false) => "__rust_u128_addo",
- (BinOp::Add, true) => "__rust_i128_addo",
- (BinOp::Sub, false) => "__rust_u128_subo",
- (BinOp::Sub, true) => "__rust_i128_subo",
- (BinOp::Mul, false) => "__rust_u128_mulo",
- _ => unreachable!(),
- };
- fx.lib_call(name, param_types, vec![], &args);
- Some(out_place.to_cvalue(fx))
+ BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => None,
+ BinOp::Add | BinOp::Sub => None,
+ BinOp::Mul => {
+ let args = [lhs.load_scalar(fx), rhs.load_scalar(fx)];
+ let ret_val = fx.lib_call(
+ "__multi3",
+ vec![AbiParam::new(types::I128), AbiParam::new(types::I128)],
+ vec![AbiParam::new(types::I128)],
+ &args,
+ )[0];
+ Some(CValue::by_val(
+ ret_val,
+ fx.layout_of(if is_signed { fx.tcx.types.i128 } else { fx.tcx.types.u128 }),
+ ))
}
BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
BinOp::Div | BinOp::Rem => {
- assert!(!checked);
let name = match (bin_op, is_signed) {
(BinOp::Div, false) => "__udivti3",
(BinOp::Div, true) => "__divti3",
@@ -100,7 +53,7 @@ pub(crate) fn maybe_codegen<'tcx>(
vec![AbiParam::new(types::I64X2)],
&args,
)[0];
- // FIXME use bitcast instead of store to get from i64x2 to i128
+ // FIXME(bytecodealliance/wasmtime#6104) use bitcast instead of store to get from i64x2 to i128
let ret_place = CPlace::new_stack_slot(fx, lhs.layout());
ret_place.to_ptr().store(fx, ret, MemFlags::trusted());
Some(ret_place.to_cvalue(fx))
@@ -115,10 +68,72 @@ pub(crate) fn maybe_codegen<'tcx>(
Some(CValue::by_val(ret_val, lhs.layout()))
}
}
- BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => {
- assert!(!checked);
- None
- }
+ BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => None,
BinOp::Shl | BinOp::Shr => None,
}
}
+
+pub(crate) fn maybe_codegen_checked<'tcx>(
+ fx: &mut FunctionCx<'_, '_, 'tcx>,
+ bin_op: BinOp,
+ lhs: CValue<'tcx>,
+ rhs: CValue<'tcx>,
+) -> Option<CValue<'tcx>> {
+ if lhs.layout().ty != fx.tcx.types.u128
+ && lhs.layout().ty != fx.tcx.types.i128
+ && rhs.layout().ty != fx.tcx.types.u128
+ && rhs.layout().ty != fx.tcx.types.i128
+ {
+ return None;
+ }
+
+ let is_signed = type_sign(lhs.layout().ty);
+
+ match bin_op {
+ BinOp::BitAnd | BinOp::BitOr | BinOp::BitXor => unreachable!(),
+ BinOp::Mul if is_signed => {
+ let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+ let oflow = CPlace::new_stack_slot(fx, fx.layout_of(fx.tcx.types.i32));
+ let lhs = lhs.load_scalar(fx);
+ let rhs = rhs.load_scalar(fx);
+ let oflow_ptr = oflow.to_ptr().get_addr(fx);
+ let res = fx.lib_call_unadjusted(
+ "__muloti4",
+ vec![
+ AbiParam::new(types::I128),
+ AbiParam::new(types::I128),
+ AbiParam::new(fx.pointer_type),
+ ],
+ vec![AbiParam::new(types::I128)],
+ &[lhs, rhs, oflow_ptr],
+ )[0];
+ let oflow = oflow.to_cvalue(fx).load_scalar(fx);
+ let oflow = fx.bcx.ins().ireduce(types::I8, oflow);
+ Some(CValue::by_val_pair(res, oflow, fx.layout_of(out_ty)))
+ }
+ BinOp::Add | BinOp::Sub | BinOp::Mul => {
+ let out_ty = fx.tcx.mk_tup(&[lhs.layout().ty, fx.tcx.types.bool]);
+ let out_place = CPlace::new_stack_slot(fx, fx.layout_of(out_ty));
+ let param_types = vec![
+ AbiParam::special(fx.pointer_type, ArgumentPurpose::StructReturn),
+ AbiParam::new(types::I128),
+ AbiParam::new(types::I128),
+ ];
+ let args = [out_place.to_ptr().get_addr(fx), lhs.load_scalar(fx), rhs.load_scalar(fx)];
+ let name = match (bin_op, is_signed) {
+ (BinOp::Add, false) => "__rust_u128_addo",
+ (BinOp::Add, true) => "__rust_i128_addo",
+ (BinOp::Sub, false) => "__rust_u128_subo",
+ (BinOp::Sub, true) => "__rust_i128_subo",
+ (BinOp::Mul, false) => "__rust_u128_mulo",
+ _ => unreachable!(),
+ };
+ fx.lib_call(name, param_types, vec![], &args);
+ Some(out_place.to_cvalue(fx))
+ }
+ BinOp::Offset => unreachable!("offset should only be used on pointers, not 128bit ints"),
+ BinOp::Div | BinOp::Rem => unreachable!(),
+ BinOp::Lt | BinOp::Le | BinOp::Eq | BinOp::Ge | BinOp::Gt | BinOp::Ne => unreachable!(),
+ BinOp::Shl | BinOp::Shr => unreachable!(),
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/common.rs b/compiler/rustc_codegen_cranelift/src/common.rs
index d39bf7000..5eaa988dd 100644
--- a/compiler/rustc_codegen_cranelift/src/common.rs
+++ b/compiler/rustc_codegen_cranelift/src/common.rs
@@ -2,7 +2,7 @@ use cranelift_codegen::isa::TargetFrontendConfig;
use gimli::write::FileId;
use rustc_data_structures::sync::Lrc;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers,
};
@@ -72,19 +72,6 @@ fn clif_type_from_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<types::Typ
pointer_ty(tcx)
}
}
- ty::Adt(adt_def, _) if adt_def.repr().simd() => {
- let (element, count) = match &tcx.layout_of(ParamEnv::reveal_all().and(ty)).unwrap().abi
- {
- Abi::Vector { element, count } => (*element, *count),
- _ => unreachable!(),
- };
-
- match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
- // Cranelift currently only implements icmp for 128bit vectors.
- Some(vector_ty) if vector_ty.bits() == 128 => vector_ty,
- _ => return None,
- }
- }
ty::Param(_) => bug!("ty param {:?}", ty),
_ => return None,
})
@@ -96,12 +83,7 @@ fn clif_pair_type_from_ty<'tcx>(
) -> Option<(types::Type, types::Type)> {
Some(match ty.kind() {
ty::Tuple(types) if types.len() == 2 => {
- let a = clif_type_from_ty(tcx, types[0])?;
- let b = clif_type_from_ty(tcx, types[1])?;
- if a.is_vector() || b.is_vector() {
- return None;
- }
- (a, b)
+ (clif_type_from_ty(tcx, types[0])?, clif_type_from_ty(tcx, types[1])?)
}
ty::RawPtr(TypeAndMut { ty: pointee_ty, mutbl: _ }) | ty::Ref(_, pointee_ty, _) => {
if has_ptr_meta(tcx, *pointee_ty) {
@@ -379,7 +361,7 @@ impl<'tcx> FunctionCx<'_, '_, 'tcx> {
self.instance.subst_mir_and_normalize_erasing_regions(
self.tcx,
ty::ParamEnv::reveal_all(),
- value,
+ ty::EarlyBinder(value),
)
}
@@ -495,7 +477,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
#[inline]
fn handle_layout_err(&self, err: LayoutError<'tcx>, span: Span, ty: Ty<'tcx>) -> ! {
if let layout::LayoutError::SizeOverflow(_) = err {
- self.0.sess.span_fatal(span, &err.to_string())
+ self.0.sess.span_fatal(span, err.to_string())
} else {
span_bug!(span, "failed to get layout for `{}`: {}", ty, err)
}
@@ -513,7 +495,7 @@ impl<'tcx> FnAbiOfHelpers<'tcx> for RevealAllLayoutCx<'tcx> {
fn_abi_request: FnAbiRequest<'tcx>,
) -> ! {
if let FnAbiError::Layout(LayoutError::SizeOverflow(_)) = err {
- self.0.sess.span_fatal(span, &err.to_string())
+ self.0.sess.span_fatal(span, err.to_string())
} else {
match fn_abi_request {
FnAbiRequest::OfFnPtr { sig, extra_args } => {
diff --git a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
index 203219a8a..d2b928db7 100644
--- a/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
+++ b/compiler/rustc_codegen_cranelift/src/concurrency_limiter.rs
@@ -25,8 +25,18 @@ impl ConcurrencyLimiter {
.clone()
.into_helper_thread(move |token| {
let mut state = state_helper.lock().unwrap();
- state.add_new_token(token.unwrap());
- available_token_condvar_helper.notify_one();
+ match token {
+ Ok(token) => {
+ state.add_new_token(token);
+ available_token_condvar_helper.notify_one();
+ }
+ Err(err) => {
+ state.poison(format!("failed to acquire jobserver token: {}", err));
+ // Notify all threads waiting for a token to give them a chance to
+ // gracefully exit.
+ available_token_condvar_helper.notify_all();
+ }
+ }
})
.unwrap();
ConcurrencyLimiter {
@@ -37,16 +47,31 @@ impl ConcurrencyLimiter {
}
}
- pub(super) fn acquire(&mut self) -> ConcurrencyLimiterToken {
+ pub(super) fn acquire(&mut self, handler: &rustc_errors::Handler) -> ConcurrencyLimiterToken {
let mut state = self.state.lock().unwrap();
loop {
state.assert_invariants();
- if state.try_start_job() {
- return ConcurrencyLimiterToken {
- state: self.state.clone(),
- available_token_condvar: self.available_token_condvar.clone(),
- };
+ match state.try_start_job() {
+ Ok(true) => {
+ return ConcurrencyLimiterToken {
+ state: self.state.clone(),
+ available_token_condvar: self.available_token_condvar.clone(),
+ };
+ }
+ Ok(false) => {}
+ Err(err) => {
+ // An error happened when acquiring the token. Raise it as fatal error.
+ // Make sure to drop the mutex guard first to prevent poisoning the mutex.
+ drop(state);
+ if let Some(err) = err {
+ handler.fatal(err).raise();
+ } else {
+ // The error was already emitted, but compilation continued. Raise a silent
+ // fatal error.
+ rustc_errors::FatalError.raise();
+ }
+ }
}
self.helper_thread.as_mut().unwrap().request_token();
@@ -100,13 +125,22 @@ mod state {
pending_jobs: usize,
active_jobs: usize,
+ poisoned: bool,
+ stored_error: Option<String>,
+
// None is used to represent the implicit token, Some to represent explicit tokens
tokens: Vec<Option<Acquired>>,
}
impl ConcurrencyLimiterState {
pub(super) fn new(pending_jobs: usize) -> Self {
- ConcurrencyLimiterState { pending_jobs, active_jobs: 0, tokens: vec![None] }
+ ConcurrencyLimiterState {
+ pending_jobs,
+ active_jobs: 0,
+ poisoned: false,
+ stored_error: None,
+ tokens: vec![None],
+ }
}
pub(super) fn assert_invariants(&self) {
@@ -127,14 +161,18 @@ mod state {
self.drop_excess_capacity();
}
- pub(super) fn try_start_job(&mut self) -> bool {
+ pub(super) fn try_start_job(&mut self) -> Result<bool, Option<String>> {
+ if self.poisoned {
+ return Err(self.stored_error.take());
+ }
+
if self.active_jobs < self.tokens.len() {
// Using existing token
self.job_started();
- return true;
+ return Ok(true);
}
- false
+ Ok(false)
}
pub(super) fn job_started(&mut self) {
@@ -161,6 +199,11 @@ mod state {
self.assert_invariants();
}
+ pub(super) fn poison(&mut self, error: String) {
+ self.poisoned = true;
+ self.stored_error = Some(error);
+ }
+
fn drop_excess_capacity(&mut self) {
self.assert_invariants();
diff --git a/compiler/rustc_codegen_cranelift/src/constant.rs b/compiler/rustc_codegen_cranelift/src/constant.rs
index e87f4e258..77af561a5 100644
--- a/compiler/rustc_codegen_cranelift/src/constant.rs
+++ b/compiler/rustc_codegen_cranelift/src/constant.rs
@@ -91,7 +91,7 @@ pub(crate) fn eval_mir_constant<'tcx>(
),
},
ConstantKind::Unevaluated(mir::UnevaluatedConst { def, .. }, _)
- if fx.tcx.is_static(def.did) =>
+ if fx.tcx.is_static(def) =>
{
span_bug!(constant.span, "MIR constant refers to static");
}
@@ -159,6 +159,8 @@ pub(crate) fn codegen_const_value<'tcx>(
_ => unreachable!(),
};
+ // FIXME avoid this extra copy to the stack and directly write to the final
+ // destination
let place = CPlace::new_stack_slot(fx, layout);
place.to_ptr().store(fx, val, MemFlags::trusted());
place.to_cvalue(fx)
@@ -306,7 +308,7 @@ fn data_id_for_static(
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
) {
Ok(data_id) => data_id,
- Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
"attempt to declare `{symbol_name}` as static, but it was already declared as function"
)),
Err(err) => Err::<_, _>(err).unwrap(),
@@ -354,7 +356,7 @@ fn data_id_for_static(
attrs.flags.contains(CodegenFnAttrFlags::THREAD_LOCAL),
) {
Ok(data_id) => data_id,
- Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(&format!(
+ Err(ModuleError::IncompatibleDeclaration(_)) => tcx.sess.fatal(format!(
"attempt to declare `{symbol_name}` as static, but it was already declared as function"
)),
Err(err) => Err::<_, _>(err).unwrap(),
@@ -402,7 +404,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
if let Some(names) = section_name.split_once(',') {
names
} else {
- tcx.sess.fatal(&format!(
+ tcx.sess.fatal(format!(
"#[link_section = \"{}\"] is not valid for macos target: must be segment and section separated by comma",
section_name
));
@@ -447,7 +449,7 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant
GlobalAlloc::Static(def_id) => {
if tcx.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL)
{
- tcx.sess.fatal(&format!(
+ tcx.sess.fatal(format!(
"Allocation {:?} contains reference to TLS value {:?}",
alloc_id, def_id
));
diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
index 3e2e2af96..aad9a9647 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs
@@ -69,7 +69,7 @@ impl OngoingCodegen {
let module_codegen_result = match module_codegen_result {
Ok(module_codegen_result) => module_codegen_result,
- Err(err) => sess.fatal(&err),
+ Err(err) => sess.fatal(err),
};
let ModuleCodegenResult { module_regular, module_global_asm, existing_work_product } =
module_codegen_result;
@@ -324,6 +324,10 @@ fn module_codegen(
OngoingModuleCodegen::Async(std::thread::spawn(move || {
cx.profiler.clone().verbose_generic_activity_with_arg("compile functions", &*cgu_name).run(
|| {
+ cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
+ cx.profiler.clone(),
+ )));
+
let mut cached_context = Context::new();
for codegened_func in codegened_functions {
crate::base::compile_fn(
@@ -407,7 +411,7 @@ pub(crate) fn run_aot(
backend_config.clone(),
global_asm_config.clone(),
cgu.name(),
- concurrency_limiter.acquire(),
+ concurrency_limiter.acquire(tcx.sess.diagnostic()),
),
module_codegen,
Some(rustc_middle::dep_graph::hash_result),
@@ -464,7 +468,7 @@ pub(crate) fn run_aot(
let obj = create_compressed_metadata_file(tcx.sess, &metadata, &symbol_name);
if let Err(err) = std::fs::write(&tmp_file, obj) {
- tcx.sess.fatal(&format!("error writing metadata object file: {}", err));
+ tcx.sess.fatal(format!("error writing metadata object file: {}", err));
}
(metadata_cgu_name, tmp_file)
diff --git a/compiler/rustc_codegen_cranelift/src/driver/jit.rs b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
index f6a48e325..3118105a4 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/jit.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/jit.rs
@@ -224,6 +224,10 @@ pub(crate) fn codegen_and_compile_fn<'tcx>(
module: &mut dyn Module,
instance: Instance<'tcx>,
) {
+ cranelift_codegen::timing::set_thread_profiler(Box::new(super::MeasuremeProfiler(
+ cx.profiler.clone(),
+ )));
+
tcx.prof.generic_activity("codegen and compile fn").run(|| {
let _inst_guard =
crate::PrintOnPanic(|| format!("{:?} {}", instance, tcx.symbol_name(instance).name));
diff --git a/compiler/rustc_codegen_cranelift/src/driver/mod.rs b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
index d09d3a529..5c52c9c18 100644
--- a/compiler/rustc_codegen_cranelift/src/driver/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/driver/mod.rs
@@ -4,6 +4,7 @@
//! [`codegen_fn`]: crate::base::codegen_fn
//! [`codegen_static`]: crate::constant::codegen_static
+use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_middle::mir::mono::{Linkage as RLinkage, MonoItem, Visibility};
use crate::prelude::*;
@@ -39,3 +40,31 @@ fn predefine_mono_items<'tcx>(
}
});
}
+
+struct MeasuremeProfiler(SelfProfilerRef);
+
+struct TimingGuard {
+ profiler: std::mem::ManuallyDrop<SelfProfilerRef>,
+ inner: Option<rustc_data_structures::profiling::TimingGuard<'static>>,
+}
+
+impl Drop for TimingGuard {
+ fn drop(&mut self) {
+ self.inner.take();
+ unsafe {
+ std::mem::ManuallyDrop::drop(&mut self.profiler);
+ }
+ }
+}
+
+impl cranelift_codegen::timing::Profiler for MeasuremeProfiler {
+ fn start_pass(&self, pass: cranelift_codegen::timing::Pass) -> Box<dyn std::any::Any> {
+ let mut timing_guard =
+ TimingGuard { profiler: std::mem::ManuallyDrop::new(self.0.clone()), inner: None };
+ timing_guard.inner = Some(
+ unsafe { &*(&*timing_guard.profiler as &SelfProfilerRef as *const SelfProfilerRef) }
+ .generic_activity(pass.description()),
+ );
+ Box::new(timing_guard)
+ }
+}
diff --git a/compiler/rustc_codegen_cranelift/src/global_asm.rs b/compiler/rustc_codegen_cranelift/src/global_asm.rs
index a74f8ffa2..63a1f6959 100644
--- a/compiler/rustc_codegen_cranelift/src/global_asm.rs
+++ b/compiler/rustc_codegen_cranelift/src/global_asm.rs
@@ -104,7 +104,6 @@ pub(crate) fn compile_global_asm(
return Ok(None);
}
- // FIXME fix linker error on macOS
if cfg!(not(feature = "inline_asm")) {
return Err(
"asm! and global_asm! support is disabled while compiling rustc_codegen_cranelift"
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
index f722e5228..f67fdb592 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm.rs
@@ -42,7 +42,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>(
_ => {
fx.tcx
.sess
- .warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
+ .warn(format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));
crate::trap::trap_unimplemented(fx, intrinsic);
return;
}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
index b431158d2..33b2f4702 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_aarch64.rs
@@ -207,7 +207,7 @@ pub(crate) fn codegen_aarch64_llvm_intrinsic_call<'tcx>(
}
*/
_ => {
- fx.tcx.sess.warn(&format!(
+ fx.tcx.sess.warn(format!(
"unsupported AArch64 llvm intrinsic {}; replacing with trap",
intrinsic
));
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
index 0f32d1a25..56d8f13ce 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/llvm_x86.rs
@@ -138,10 +138,9 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>(
llvm_add_sub(fx, BinOp::Sub, ret, b_in, a, b);
}
_ => {
- fx.tcx.sess.warn(&format!(
- "unsupported x86 llvm intrinsic {}; replacing with trap",
- intrinsic
- ));
+ fx.tcx
+ .sess
+ .warn(format!("unsupported x86 llvm intrinsic {}; replacing with trap", intrinsic));
crate::trap::trap_unimplemented(fx, intrinsic);
return;
}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
index 03f2a65fc..0a513b08b 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/mod.rs
@@ -42,7 +42,7 @@ fn report_atomic_type_validation_error<'tcx>(
) {
fx.tcx.sess.span_err(
span,
- &format!(
+ format!(
"`{}` intrinsic: expected basic integer or raw pointer type, found `{:?}`",
intrinsic, ty
),
@@ -51,17 +51,13 @@ fn report_atomic_type_validation_error<'tcx>(
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
-pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Option<Type> {
+pub(crate) fn clif_vector_type<'tcx>(tcx: TyCtxt<'tcx>, layout: TyAndLayout<'tcx>) -> Type {
let (element, count) = match layout.abi {
Abi::Vector { element, count } => (element, count),
_ => unreachable!(),
};
- match scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()) {
- // Cranelift currently only implements icmp for 128bit vectors.
- Some(vector_ty) if vector_ty.bits() == 128 => Some(vector_ty),
- _ => None,
- }
+ scalar_to_clif_type(tcx, element).by(u32::try_from(count).unwrap()).unwrap()
}
fn simd_for_each_lane<'tcx>(
@@ -534,7 +530,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
// The only difference between offset and arith_offset is regarding UB. Because Cranelift
// doesn't have UB both are codegen'ed the same way
- sym::offset | sym::arith_offset => {
+ sym::arith_offset => {
intrinsic_args!(fx, args => (base, offset); intrinsic);
let offset = offset.load_scalar(fx);
@@ -1107,8 +1103,8 @@ fn codegen_regular_intrinsic_call<'tcx>(
fx.bcx.ins().call_indirect(f_sig, f, &[data]);
- let layout = ret.layout();
- let ret_val = CValue::const_val(fx, layout, ty::ScalarInt::null(layout.size));
+ let layout = fx.layout_of(fx.tcx.types.i32);
+ let ret_val = CValue::by_val(fx.bcx.ins().iconst(types::I32, 0), layout);
ret.write_cvalue(fx, ret_val);
}
@@ -1206,7 +1202,7 @@ fn codegen_regular_intrinsic_call<'tcx>(
_ => {
fx.tcx
.sess
- .span_fatal(source_info.span, &format!("unsupported intrinsic {}", intrinsic));
+ .span_fatal(source_info.span, format!("unsupported intrinsic {}", intrinsic));
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
index 6f54a8d49..5a038bfca 100644
--- a/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
+++ b/compiler/rustc_codegen_cranelift/src/intrinsics/simd.rs
@@ -13,7 +13,7 @@ fn report_simd_type_validation_error(
span: Span,
ty: Ty<'_>,
) {
- fx.tcx.sess.span_err(span, &format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
+ fx.tcx.sess.span_err(span, format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty));
// Prevent verifier error
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
@@ -150,7 +150,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
_ => {
fx.tcx.sess.span_err(
span,
- &format!(
+ format!(
"simd_shuffle index must be an array of `u32`, got `{}`",
idx_ty,
),
@@ -248,12 +248,12 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(
fx.mir.span,
- &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
+ format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count),
);
}
ret.write_cvalue(fx, base);
- let ret_lane = ret.place_field(fx, FieldIdx::new(idx.try_into().unwrap()));
+ let ret_lane = ret.place_lane(fx, idx.try_into().unwrap());
ret_lane.write_cvalue(fx, val);
}
@@ -296,7 +296,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
if idx >= lane_count.into() {
fx.tcx.sess.span_fatal(
fx.mir.span,
- &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
+ format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count),
);
}
@@ -699,7 +699,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
_ => {
fx.tcx.sess.span_fatal(
span,
- &format!(
+ format!(
"invalid monomorphization of `simd_bitmask` intrinsic: \
vector argument `{}`'s element type `{}`, expected integer element \
type",
@@ -739,7 +739,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
_ => {
fx.tcx.sess.span_fatal(
span,
- &format!(
+ format!(
"invalid monomorphization of `simd_bitmask` intrinsic: \
cannot return `{}`, expected `u{}` or `[u8; {}]`",
ret.layout().ty,
@@ -875,7 +875,7 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>(
}
_ => {
- fx.tcx.sess.span_err(span, &format!("Unknown SIMD intrinsic {}", intrinsic));
+ fx.tcx.sess.span_err(span, format!("Unknown SIMD intrinsic {}", intrinsic));
// Prevent verifier error
fx.bcx.ins().trap(TrapCode::UnreachableCodeReached);
}
diff --git a/compiler/rustc_codegen_cranelift/src/lib.rs b/compiler/rustc_codegen_cranelift/src/lib.rs
index 8cc7f6c34..9966cc2ef 100644
--- a/compiler/rustc_codegen_cranelift/src/lib.rs
+++ b/compiler/rustc_codegen_cranelift/src/lib.rs
@@ -90,7 +90,7 @@ mod prelude {
pub(crate) use rustc_data_structures::fx::FxHashMap;
- pub(crate) use rustc_index::vec::Idx;
+ pub(crate) use rustc_index::Idx;
pub(crate) use cranelift_codegen::ir::condcodes::{FloatCC, IntCC};
pub(crate) use cranelift_codegen::ir::function::Function;
@@ -110,7 +110,7 @@ mod prelude {
pub(crate) use crate::common::*;
pub(crate) use crate::debuginfo::{DebugContext, UnwindContext};
pub(crate) use crate::pointer::Pointer;
- pub(crate) use crate::value_and_place::{CPlace, CPlaceInner, CValue};
+ pub(crate) use crate::value_and_place::{CPlace, CValue};
}
struct PrintOnPanic<F: Fn() -> String>(F);
@@ -185,7 +185,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
let mut config = self.config.borrow_mut();
if config.is_none() {
let new_config = BackendConfig::from_opts(&sess.opts.cg.llvm_args)
- .unwrap_or_else(|err| sess.fatal(&err));
+ .unwrap_or_else(|err| sess.fatal(err));
*config = Some(new_config);
}
}
@@ -245,7 +245,7 @@ impl CodegenBackend for CraneliftCodegenBackend {
fn target_triple(sess: &Session) -> target_lexicon::Triple {
match sess.target.llvm_target.parse() {
Ok(triple) => triple,
- Err(err) => sess.fatal(&format!("target not recognized: {}", err)),
+ Err(err) => sess.fatal(format!("target not recognized: {}", err)),
}
}
@@ -307,7 +307,7 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
Some(value) => {
let mut builder =
cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
- sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
+ sess.fatal(format!("can't compile for {}: {}", target_triple, err));
});
if let Err(_) = builder.enable(value) {
sess.fatal("the specified target cpu isn't currently supported by Cranelift.");
@@ -317,7 +317,7 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
None => {
let mut builder =
cranelift_codegen::isa::lookup(target_triple.clone()).unwrap_or_else(|err| {
- sess.fatal(&format!("can't compile for {}: {}", target_triple, err));
+ sess.fatal(format!("can't compile for {}: {}", target_triple, err));
});
if target_triple.architecture == target_lexicon::Architecture::X86_64 {
// Don't use "haswell" as the default, as it implies `has_lzcnt`.
@@ -330,7 +330,7 @@ fn build_isa(sess: &Session, backend_config: &BackendConfig) -> Arc<dyn isa::Tar
match isa_builder.finish(flags) {
Ok(target_isa) => target_isa,
- Err(err) => sess.fatal(&format!("failed to build TargetIsa: {}", err)),
+ Err(err) => sess.fatal(format!("failed to build TargetIsa: {}", err)),
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/main_shim.rs b/compiler/rustc_codegen_cranelift/src/main_shim.rs
index 205411e8c..20ba73f38 100644
--- a/compiler/rustc_codegen_cranelift/src/main_shim.rs
+++ b/compiler/rustc_codegen_cranelift/src/main_shim.rs
@@ -75,7 +75,7 @@ pub(crate) fn maybe_create_entry_wrapper(
Ok(func_id) => func_id,
Err(err) => {
tcx.sess
- .fatal(&format!("entry symbol `{entry_name}` declared multiple times: {err}"));
+ .fatal(format!("entry symbol `{entry_name}` declared multiple times: {err}"));
}
};
@@ -171,7 +171,7 @@ pub(crate) fn maybe_create_entry_wrapper(
}
if let Err(err) = m.define_function(cmain_func_id, &mut ctx) {
- tcx.sess.fatal(&format!("entry symbol `{entry_name}` defined multiple times: {err}"));
+ tcx.sess.fatal(format!("entry symbol `{entry_name}` defined multiple times: {err}"));
}
unwind_context.add_function(cmain_func_id, &ctx, m.isa());
diff --git a/compiler/rustc_codegen_cranelift/src/num.rs b/compiler/rustc_codegen_cranelift/src/num.rs
index 1357b7be1..ba53e01c7 100644
--- a/compiler/rustc_codegen_cranelift/src/num.rs
+++ b/compiler/rustc_codegen_cranelift/src/num.rs
@@ -118,7 +118,7 @@ pub(crate) fn codegen_int_binop<'tcx>(
);
}
- if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, false, in_lhs, in_rhs) {
+ if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, in_lhs, in_rhs) {
return res;
}
@@ -173,7 +173,7 @@ pub(crate) fn codegen_checked_int_binop<'tcx>(
let lhs = in_lhs.load_scalar(fx);
let rhs = in_rhs.load_scalar(fx);
- if let Some(res) = crate::codegen_i128::maybe_codegen(fx, bin_op, true, in_lhs, in_rhs) {
+ if let Some(res) = crate::codegen_i128::maybe_codegen_checked(fx, bin_op, in_lhs, in_rhs) {
return res;
}
diff --git a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
index e0a081c9d..1007b33ec 100644
--- a/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
+++ b/compiler/rustc_codegen_cranelift/src/pretty_clif.rs
@@ -7,48 +7,51 @@
//! test compile
//! target x86_64
//!
-//! function u0:0(i64, i64, i64) system_v {
-//! ; symbol _ZN119_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$u27$a$u20$$RF$$u27$b$u20$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17he85059d5e6a760a0E
-//! ; instance Instance { def: Item(DefId(0/0:29 ~ example[8787]::{{impl}}[0]::call_once[0])), substs: [ReErased, ReErased] }
-//! ; sig ([IsNotEmpty, (&&[u16],)]; c_variadic: false)->(u8, u8)
+//! function u0:22(i64) -> i8, i8 system_v {
+//! ; symbol _ZN97_$LT$example..IsNotEmpty$u20$as$u20$mini_core..FnOnce$LT$$LP$$RF$$RF$$u5b$u16$u5d$$C$$RP$$GT$$GT$9call_once17hd517c453d67c0915E
+//! ; instance Instance { def: Item(WithOptConstParam { did: DefId(0:42 ~ example[4e51]::{impl#0}::call_once), const_param_did: None }), substs: [ReErased, ReErased] }
+//! ; abi FnAbi { args: [ArgAbi { layout: TyAndLayout { ty: IsNotEmpty, layout: Layout { size: Size(0 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: Aggregate { sized: true }, fields: Arbitrary { offsets: [], memory_index: [] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Ignore }, ArgAbi { layout: TyAndLayout { ty: &&[u16], layout: Layout { size: Size(8 bytes), align: AbiAndPrefAlign { abi: Align(8 bytes), pref: Align(8 bytes) }, abi: Scalar(Initialized { value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), fields: Primitive, largest_niche: Some(Niche { offset: Size(0 bytes), value: Pointer(AddressSpace(0)), valid_range: 1..=18446744073709551615 }), variants: Single { index: 0 } } }, mode: Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) }], ret: ArgAbi { layout: TyAndLayout { ty: (u8, u8), layout: Layout { size: Size(2 bytes), align: AbiAndPrefAlign { abi: Align(1 bytes), pref: Align(8 bytes) }, abi: ScalarPair(Initialized { value: Int(I8, false), valid_range: 0..=255 }, Initialized { value: Int(I8, false), valid_range: 0..=255 }), fields: Arbitrary { offsets: [Size(0 bytes), Size(1 bytes)], memory_index: [0, 1] }, largest_niche: None, variants: Single { index: 0 } } }, mode: Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) }, c_variadic: false, fixed_count: 1, conv: Rust, can_unwind: false }
//!
-//! ; ssa {_2: NOT_SSA, _4: NOT_SSA, _0: NOT_SSA, _3: (empty), _1: NOT_SSA}
-//! ; msg loc.idx param pass mode ssa flags ty
-//! ; ret _0 = v0 ByRef NOT_SSA (u8, u8)
-//! ; arg _1 = v1 ByRef NOT_SSA IsNotEmpty
-//! ; arg _2.0 = v2 ByVal(types::I64) NOT_SSA &&[u16]
+//! ; kind loc.idx param pass mode ty
+//! ; ssa _0 (u8, u8) 2b 1, 8 var=(0, 1)
+//! ; ret _0 - Pair(ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }, ArgAttributes { regular: NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: None }) (u8, u8)
+//! ; arg _1 - Ignore IsNotEmpty
+//! ; arg _2.0 = v0 Direct(ArgAttributes { regular: NonNull | NoUndef, arg_ext: None, pointee_size: Size(0 bytes), pointee_align: Some(Align(8 bytes)) }) &&[u16]
//!
-//! ss0 = explicit_slot 0 ; _1: IsNotEmpty size=0 align=1,8
-//! ss1 = explicit_slot 8 ; _2: (&&[u16],) size=8 align=8,8
-//! ss2 = explicit_slot 8 ; _4: (&&[u16],) size=8 align=8,8
-//! sig0 = (i64, i64, i64) system_v
-//! sig1 = (i64, i64, i64) system_v
-//! fn0 = colocated u0:6 sig1 ; Instance { def: Item(DefId(0/0:31 ~ example[8787]::{{impl}}[1]::call_mut[0])), substs: [ReErased, ReErased] }
+//! ; kind local ty size align (abi,pref)
+//! ; zst _1 IsNotEmpty 0b 1, 8 align=8,offset=
+//! ; stack _2 (&&[u16],) 8b 8, 8 storage=ss0
+//! ; ssa _3 &mut IsNotEmpty 8b 8, 8 var=2
//!
-//! block0(v0: i64, v1: i64, v2: i64):
-//! v3 = stack_addr.i64 ss0
-//! v4 = stack_addr.i64 ss1
-//! store v2, v4
-//! v5 = stack_addr.i64 ss2
+//! ss0 = explicit_slot 16
+//! sig0 = (i64, i64) -> i8, i8 system_v
+//! fn0 = colocated u0:23 sig0 ; Instance { def: Item(WithOptConstParam { did: DefId(0:46 ~ example[4e51]::{impl#1}::call_mut), const_param_did: None }), substs: [ReErased, ReErased] }
+//!
+//! block0(v0: i64):
+//! nop
+//! ; write_cvalue: Addr(Pointer { base: Stack(ss0), offset: Offset32(0) }, None): &&[u16] <- ByVal(v0): &&[u16]
+//! stack_store v0, ss0
//! jump block1
//!
//! block1:
//! nop
//! ; _3 = &mut _1
-//! ; _4 = _2
-//! v6 = load.i64 v4
-//! store v6, v5
+//! v1 = iconst.i64 8
+//! ; write_cvalue: Var(_3, var2): &mut IsNotEmpty <- ByVal(v1): &mut IsNotEmpty
//! ;
-//! ; _0 = const mini_core::FnMut::call_mut(move _3, move _4)
-//! v7 = load.i64 v5
-//! call fn0(v0, v3, v7)
+//! ; _0 = <IsNotEmpty as mini_core::FnMut<(&&[u16],)>>::call_mut(move _3, _2)
+//! v2 = stack_load.i64 ss0
+//! v3, v4 = call fn0(v1, v2) ; v1 = 8
+//! v5 -> v3
+//! v6 -> v4
+//! ; write_cvalue: VarPair(_0, var0, var1): (u8, u8) <- ByValPair(v3, v4): (u8, u8)
//! jump block2
//!
//! block2:
//! nop
//! ;
//! ; return
-//! return
+//! return v5, v6
//! }
//! ```
@@ -224,7 +227,7 @@ pub(crate) fn write_ir_file(
// Using early_warn as no Session is available here
rustc_session::early_warn(
rustc_session::config::ErrorOutputType::default(),
- &format!("error writing ir file: {}", err),
+ format!("error writing ir file: {}", err),
);
}
}
diff --git a/compiler/rustc_codegen_cranelift/src/value_and_place.rs b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
index 1b69862ce..b1fda6ff2 100644
--- a/compiler/rustc_codegen_cranelift/src/value_and_place.rs
+++ b/compiler/rustc_codegen_cranelift/src/value_and_place.rs
@@ -2,8 +2,8 @@
use crate::prelude::*;
+use cranelift_codegen::entity::EntityRef;
use cranelift_codegen::ir::immediates::Offset32;
-use cranelift_codegen::ir::{InstructionData, Opcode};
fn codegen_field<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -214,17 +214,7 @@ impl<'tcx> CValue<'tcx> {
) -> CValue<'tcx> {
let layout = self.1;
match self.0 {
- CValueInner::ByVal(val) => match layout.abi {
- Abi::Vector { element: _, count } => {
- let count = u8::try_from(count).expect("SIMD type with more than 255 lanes???");
- let field = u8::try_from(field.index()).unwrap();
- assert!(field < count);
- let lane = fx.bcx.ins().extractlane(val, field);
- let field_layout = layout.field(&*fx, usize::from(field));
- CValue::by_val(lane, field_layout)
- }
- _ => unreachable!("value_field for ByVal with abi {:?}", layout.abi),
- },
+ CValueInner::ByVal(_) => unreachable!(),
CValueInner::ByValPair(val1, val2) => match layout.abi {
Abi::ScalarPair(_, _) => {
let val = match field.as_u32() {
@@ -258,16 +248,7 @@ impl<'tcx> CValue<'tcx> {
let lane_layout = fx.layout_of(lane_ty);
assert!(lane_idx < lane_count);
match self.0 {
- CValueInner::ByVal(val) => match layout.abi {
- Abi::Vector { element: _, count: _ } => {
- assert!(lane_count <= u8::MAX.into(), "SIMD type with more than 255 lanes???");
- let lane_idx = u8::try_from(lane_idx).unwrap();
- let lane = fx.bcx.ins().extractlane(val, lane_idx);
- CValue::by_val(lane, lane_layout)
- }
- _ => unreachable!("value_lane for ByVal with abi {:?}", layout.abi),
- },
- CValueInner::ByValPair(_, _) => unreachable!(),
+ CValueInner::ByVal(_) | CValueInner::ByValPair(_, _) => unreachable!(),
CValueInner::ByRef(ptr, None) => {
let field_offset = lane_layout.size * lane_idx;
let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
@@ -277,14 +258,6 @@ impl<'tcx> CValue<'tcx> {
}
}
- pub(crate) fn unsize_value(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
- crate::unsize::coerce_unsized_into(fx, self, dest);
- }
-
- pub(crate) fn coerce_dyn_star(self, fx: &mut FunctionCx<'_, '_, 'tcx>, dest: CPlace<'tcx>) {
- crate::unsize::coerce_dyn_star(fx, self, dest);
- }
-
/// If `ty` is signed, `const_val` must already be sign extended.
pub(crate) fn const_val(
fx: &mut FunctionCx<'_, '_, 'tcx>,
@@ -345,10 +318,9 @@ pub(crate) struct CPlace<'tcx> {
}
#[derive(Debug, Copy, Clone)]
-pub(crate) enum CPlaceInner {
+enum CPlaceInner {
Var(Local, Variable),
VarPair(Local, Variable, Variable),
- VarLane(Local, Variable, u8),
Addr(Pointer, Option<Value>),
}
@@ -357,10 +329,6 @@ impl<'tcx> CPlace<'tcx> {
self.layout
}
- pub(crate) fn inner(&self) -> &CPlaceInner {
- &self.inner
- }
-
pub(crate) fn new_stack_slot(
fx: &mut FunctionCx<'_, '_, 'tcx>,
layout: TyAndLayout<'tcx>,
@@ -376,7 +344,7 @@ impl<'tcx> CPlace<'tcx> {
if layout.size.bytes() >= u64::from(u32::MAX - 16) {
fx.tcx
.sess
- .fatal(&format!("values of type {} are too big to store on the stack", layout.ty));
+ .fatal(format!("values of type {} are too big to store on the stack", layout.ty));
}
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
@@ -442,12 +410,6 @@ impl<'tcx> CPlace<'tcx> {
//fx.bcx.set_val_label(val2, cranelift_codegen::ir::ValueLabel::new(var2.index()));
CValue::by_val_pair(val1, val2, layout)
}
- CPlaceInner::VarLane(_local, var, lane) => {
- let val = fx.bcx.use_var(var);
- //fx.bcx.set_val_label(val, cranelift_codegen::ir::ValueLabel::new(var.index()));
- let val = fx.bcx.ins().extractlane(val, lane);
- CValue::by_val(val, layout)
- }
CPlaceInner::Addr(ptr, extra) => {
if let Some(extra) = extra {
CValue::by_ref_unsized(ptr, extra, layout)
@@ -458,21 +420,56 @@ impl<'tcx> CPlace<'tcx> {
}
}
+ pub(crate) fn debug_comment(self) -> (&'static str, String) {
+ match self.inner {
+ CPlaceInner::Var(_local, var) => ("ssa", format!("var={}", var.index())),
+ CPlaceInner::VarPair(_local, var1, var2) => {
+ ("ssa", format!("var=({}, {})", var1.index(), var2.index()))
+ }
+ CPlaceInner::Addr(ptr, meta) => {
+ let meta =
+ if let Some(meta) = meta { format!(",meta={}", meta) } else { String::new() };
+ match ptr.debug_base_and_offset() {
+ (crate::pointer::PointerBase::Addr(addr), offset) => {
+ ("reuse", format!("storage={}{}{}", addr, offset, meta))
+ }
+ (crate::pointer::PointerBase::Stack(stack_slot), offset) => {
+ ("stack", format!("storage={}{}{}", stack_slot, offset, meta))
+ }
+ (crate::pointer::PointerBase::Dangling(align), offset) => {
+ ("zst", format!("align={},offset={}", align.bytes(), offset))
+ }
+ }
+ }
+ }
+ }
+
#[track_caller]
pub(crate) fn to_ptr(self) -> Pointer {
- match self.to_ptr_maybe_unsized() {
- (ptr, None) => ptr,
- (_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
+ match self.inner {
+ CPlaceInner::Addr(ptr, None) => ptr,
+ CPlaceInner::Addr(_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
+ CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+ bug!("Expected CPlace::Addr, found {:?}", self)
+ }
}
}
#[track_caller]
- pub(crate) fn to_ptr_maybe_unsized(self) -> (Pointer, Option<Value>) {
+ pub(crate) fn to_ptr_unsized(self) -> (Pointer, Value) {
match self.inner {
- CPlaceInner::Addr(ptr, extra) => (ptr, extra),
- CPlaceInner::Var(_, _)
- | CPlaceInner::VarPair(_, _, _)
- | CPlaceInner::VarLane(_, _, _) => bug!("Expected CPlace::Addr, found {:?}", self),
+ CPlaceInner::Addr(ptr, Some(extra)) => (ptr, extra),
+ CPlaceInner::Addr(_, None) | CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+ bug!("Expected unsized cplace, found {:?}", self)
+ }
+ }
+ }
+
+ pub(crate) fn try_to_ptr(self) -> Option<Pointer> {
+ match self.inner {
+ CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => None,
+ CPlaceInner::Addr(ptr, None) => Some(ptr),
+ CPlaceInner::Addr(_, Some(_)) => bug!("Expected sized cplace, found {:?}", self),
}
}
@@ -496,7 +493,7 @@ impl<'tcx> CPlace<'tcx> {
from: CValue<'tcx>,
method: &'static str,
) {
- fn transmute_value<'tcx>(
+ fn transmute_scalar<'tcx>(
fx: &mut FunctionCx<'_, '_, 'tcx>,
var: Variable,
data: Value,
@@ -520,7 +517,7 @@ impl<'tcx> CPlace<'tcx> {
| (types::F64, types::I64) => codegen_bitcast(fx, dst_ty, data),
_ if src_ty.is_vector() && dst_ty.is_vector() => codegen_bitcast(fx, dst_ty, data),
_ if src_ty.is_vector() || dst_ty.is_vector() => {
- // FIXME do something more efficient for transmutes between vectors and integers.
+ // FIXME(bytecodealliance/wasmtime#6104) do something more efficient for transmutes between vectors and integers.
let stack_slot = fx.bcx.create_sized_stack_slot(StackSlotData {
kind: StackSlotKind::ExplicitSlot,
// FIXME Don't force the size to a multiple of 16 bytes once Cranelift gets a way to
@@ -554,7 +551,7 @@ impl<'tcx> CPlace<'tcx> {
format!(
"{}: {:?}: {:?} <- {:?}: {:?}",
method,
- self.inner(),
+ self.inner,
self.layout().ty,
from.0,
from.layout().ty
@@ -563,32 +560,11 @@ impl<'tcx> CPlace<'tcx> {
}
let dst_layout = self.layout();
- let to_ptr = match self.inner {
+ match self.inner {
CPlaceInner::Var(_local, var) => {
- if let ty::Array(element, len) = dst_layout.ty.kind() {
- // Can only happen for vector types
- let len = u32::try_from(len.eval_target_usize(fx.tcx, ParamEnv::reveal_all()))
- .unwrap();
- let vector_ty = fx.clif_type(*element).unwrap().by(len).unwrap();
-
- let data = match from.0 {
- CValueInner::ByRef(ptr, None) => {
- let mut flags = MemFlags::new();
- flags.set_notrap();
- ptr.load(fx, vector_ty, flags)
- }
- CValueInner::ByVal(_)
- | CValueInner::ByValPair(_, _)
- | CValueInner::ByRef(_, Some(_)) => bug!("array should be ByRef"),
- };
-
- fx.bcx.def_var(var, data);
- return;
- }
let data = CValue(from.0, dst_layout).load_scalar(fx);
let dst_ty = fx.clif_type(self.layout().ty).unwrap();
- transmute_value(fx, var, data, dst_ty);
- return;
+ transmute_scalar(fx, var, data, dst_ty);
}
CPlaceInner::VarPair(_local, var1, var2) => {
let (data1, data2) = if from.layout().ty == dst_layout.ty {
@@ -599,80 +575,61 @@ impl<'tcx> CPlace<'tcx> {
CValue(CValueInner::ByRef(ptr, None), dst_layout).load_scalar_pair(fx)
};
let (dst_ty1, dst_ty2) = fx.clif_pair_type(self.layout().ty).unwrap();
- transmute_value(fx, var1, data1, dst_ty1);
- transmute_value(fx, var2, data2, dst_ty2);
- return;
+ transmute_scalar(fx, var1, data1, dst_ty1);
+ transmute_scalar(fx, var2, data2, dst_ty2);
}
- CPlaceInner::VarLane(_local, var, lane) => {
- let data = from.load_scalar(fx);
-
- // First get the old vector
- let vector = fx.bcx.use_var(var);
- //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
-
- // Next insert the written lane into the vector
- let vector = fx.bcx.ins().insertlane(vector, data, lane);
-
- // Finally write the new vector
- //fx.bcx.set_val_label(vector, cranelift_codegen::ir::ValueLabel::new(var.index()));
- fx.bcx.def_var(var, vector);
-
- return;
- }
- CPlaceInner::Addr(ptr, None) => {
+ CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
+ CPlaceInner::Addr(to_ptr, None) => {
if dst_layout.size == Size::ZERO || dst_layout.abi == Abi::Uninhabited {
return;
}
- ptr
- }
- CPlaceInner::Addr(_, Some(_)) => bug!("Can't write value to unsized place {:?}", self),
- };
- let mut flags = MemFlags::new();
- flags.set_notrap();
- match from.layout().abi {
- // FIXME make Abi::Vector work too
- Abi::Scalar(_) => {
- let val = from.load_scalar(fx);
- to_ptr.store(fx, val, flags);
- return;
- }
- Abi::ScalarPair(a_scalar, b_scalar) => {
- let (value, extra) = from.load_scalar_pair(fx);
- let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
- to_ptr.store(fx, value, flags);
- to_ptr.offset(fx, b_offset).store(fx, extra, flags);
- return;
- }
- _ => {}
- }
+ let mut flags = MemFlags::new();
+ flags.set_notrap();
+ match from.layout().abi {
+ Abi::Scalar(_) => {
+ let val = from.load_scalar(fx);
+ to_ptr.store(fx, val, flags);
+ return;
+ }
+ Abi::ScalarPair(a_scalar, b_scalar) => {
+ let (value, extra) = from.load_scalar_pair(fx);
+ let b_offset = scalar_pair_calculate_b_offset(fx.tcx, a_scalar, b_scalar);
+ to_ptr.store(fx, value, flags);
+ to_ptr.offset(fx, b_offset).store(fx, extra, flags);
+ return;
+ }
+ _ => {}
+ }
- match from.0 {
- CValueInner::ByVal(val) => {
- to_ptr.store(fx, val, flags);
- }
- CValueInner::ByValPair(_, _) => {
- bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi);
- }
- CValueInner::ByRef(from_ptr, None) => {
- let from_addr = from_ptr.get_addr(fx);
- let to_addr = to_ptr.get_addr(fx);
- let src_layout = from.1;
- let size = dst_layout.size.bytes();
- let src_align = src_layout.align.abi.bytes() as u8;
- let dst_align = dst_layout.align.abi.bytes() as u8;
- fx.bcx.emit_small_memory_copy(
- fx.target_config,
- to_addr,
- from_addr,
- size,
- dst_align,
- src_align,
- true,
- flags,
- );
+ match from.0 {
+ CValueInner::ByVal(val) => {
+ to_ptr.store(fx, val, flags);
+ }
+ CValueInner::ByValPair(_, _) => {
+ bug!("Non ScalarPair abi {:?} for ByValPair CValue", dst_layout.abi);
+ }
+ CValueInner::ByRef(from_ptr, None) => {
+ let from_addr = from_ptr.get_addr(fx);
+ let to_addr = to_ptr.get_addr(fx);
+ let src_layout = from.1;
+ let size = dst_layout.size.bytes();
+ let src_align = src_layout.align.abi.bytes() as u8;
+ let dst_align = dst_layout.align.abi.bytes() as u8;
+ fx.bcx.emit_small_memory_copy(
+ fx.target_config,
+ to_addr,
+ from_addr,
+ size,
+ dst_align,
+ src_align,
+ true,
+ flags,
+ );
+ }
+ CValueInner::ByRef(_, Some(_)) => todo!(),
+ }
}
- CValueInner::ByRef(_, Some(_)) => todo!(),
}
}
@@ -692,40 +649,6 @@ impl<'tcx> CPlace<'tcx> {
let layout = self.layout();
match self.inner {
- CPlaceInner::Var(local, var) => match layout.ty.kind() {
- ty::Array(_, _) => {
- // Can only happen for vector types
- return CPlace {
- inner: CPlaceInner::VarLane(local, var, field.as_u32().try_into().unwrap()),
- layout: layout.field(fx, field.as_u32().try_into().unwrap()),
- };
- }
- ty::Adt(adt_def, substs) if layout.ty.is_simd() => {
- let f0 = &adt_def.non_enum_variant().fields[FieldIdx::from_u32(0)];
- let f0_ty = f0.ty(fx.tcx, substs);
-
- match f0_ty.kind() {
- ty::Array(_, _) => {
- assert_eq!(field.as_u32(), 0);
- return CPlace {
- inner: CPlaceInner::Var(local, var),
- layout: layout.field(fx, field.as_u32().try_into().unwrap()),
- };
- }
- _ => {
- return CPlace {
- inner: CPlaceInner::VarLane(
- local,
- var,
- field.as_u32().try_into().unwrap(),
- ),
- layout: layout.field(fx, field.as_u32().try_into().unwrap()),
- };
- }
- }
- }
- _ => {}
- },
CPlaceInner::VarPair(local, var1, var2) => {
let layout = layout.field(&*fx, field.index());
@@ -738,7 +661,12 @@ impl<'tcx> CPlace<'tcx> {
_ => {}
}
- let (base, extra) = self.to_ptr_maybe_unsized();
+ let (base, extra) = match self.inner {
+ CPlaceInner::Addr(ptr, extra) => (ptr, extra),
+ CPlaceInner::Var(_, _) | CPlaceInner::VarPair(_, _, _) => {
+ bug!("Expected CPlace::Addr, found {:?}", self)
+ }
+ };
let (field_ptr, field_layout) = codegen_field(fx, base, extra, layout, field);
if field_layout.is_unsized() {
@@ -767,15 +695,8 @@ impl<'tcx> CPlace<'tcx> {
assert!(lane_idx < lane_count);
match self.inner {
- CPlaceInner::Var(local, var) => {
- assert!(matches!(layout.abi, Abi::Vector { .. }));
- CPlace {
- inner: CPlaceInner::VarLane(local, var, lane_idx.try_into().unwrap()),
- layout: lane_layout,
- }
- }
+ CPlaceInner::Var(_, _) => unreachable!(),
CPlaceInner::VarPair(_, _, _) => unreachable!(),
- CPlaceInner::VarLane(_, _, _) => unreachable!(),
CPlaceInner::Addr(ptr, None) => {
let field_offset = lane_layout.size * lane_idx;
let field_ptr = ptr.offset_i64(fx, i64::try_from(field_offset.bytes()).unwrap());
@@ -794,34 +715,13 @@ impl<'tcx> CPlace<'tcx> {
ty::Array(elem_ty, _) => {
let elem_layout = fx.layout_of(*elem_ty);
match self.inner {
- CPlaceInner::Var(local, var) => {
- // This is a hack to handle `vector_val.0[1]`. It doesn't allow dynamic
- // indexing.
- let lane_idx = match fx.bcx.func.dfg.insts
- [fx.bcx.func.dfg.value_def(index).unwrap_inst()]
- {
- InstructionData::UnaryImm { opcode: Opcode::Iconst, imm } => imm,
- _ => bug!(
- "Dynamic indexing into a vector type is not supported: {self:?}[{index}]"
- ),
- };
- return CPlace {
- inner: CPlaceInner::VarLane(
- local,
- var,
- lane_idx.bits().try_into().unwrap(),
- ),
- layout: elem_layout,
- };
- }
CPlaceInner::Addr(addr, None) => (elem_layout, addr),
- CPlaceInner::Addr(_, Some(_))
- | CPlaceInner::VarPair(_, _, _)
- | CPlaceInner::VarLane(_, _, _) => bug!("Can't index into {self:?}"),
+ CPlaceInner::Var(_, _)
+ | CPlaceInner::Addr(_, Some(_))
+ | CPlaceInner::VarPair(_, _, _) => bug!("Can't index into {self:?}"),
}
- // FIXME use VarLane in case of Var with simd type
}
- ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_maybe_unsized().0),
+ ty::Slice(elem_ty) => (fx.layout_of(*elem_ty), self.to_ptr_unsized().0),
_ => bug!("place_index({:?})", self.layout().ty),
};
@@ -846,12 +746,8 @@ impl<'tcx> CPlace<'tcx> {
layout: TyAndLayout<'tcx>,
) -> CValue<'tcx> {
if has_ptr_meta(fx.tcx, self.layout().ty) {
- let (ptr, extra) = self.to_ptr_maybe_unsized();
- CValue::by_val_pair(
- ptr.get_addr(fx),
- extra.expect("unsized type without metadata"),
- layout,
- )
+ let (ptr, extra) = self.to_ptr_unsized();
+ CValue::by_val_pair(ptr.get_addr(fx), extra, layout)
} else {
CValue::by_val(self.to_ptr().get_addr(fx), layout)
}
diff --git a/compiler/rustc_codegen_cranelift/y.rs b/compiler/rustc_codegen_cranelift/y.rs
index fd825d02e..a68a10500 100755
--- a/compiler/rustc_codegen_cranelift/y.rs
+++ b/compiler/rustc_codegen_cranelift/y.rs
@@ -3,10 +3,14 @@
# This block is ignored by rustc
set -e
echo "[BUILD] y.rs" 1>&2
-rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021 -Cpanic=abort
+rustc $0 -o ${0/.rs/.bin} -Cdebuginfo=1 --edition 2021
exec ${0/.rs/.bin} $@
*/
+#![warn(rust_2018_idioms)]
+#![warn(unused_lifetimes)]
+#![warn(unreachable_pub)]
+
//! The build system for cg_clif
//!
//! # Manual compilation
diff --git a/compiler/rustc_codegen_gcc/messages.ftl b/compiler/rustc_codegen_gcc/messages.ftl
index 0a94a08f8..97bc8ef9d 100644
--- a/compiler/rustc_codegen_gcc/messages.ftl
+++ b/compiler/rustc_codegen_gcc/messages.ftl
@@ -1,68 +1,68 @@
-codegen_gcc_unwinding_inline_asm =
- GCC backend does not support unwinding from inline asm
-
-codegen_gcc_lto_not_supported =
- LTO is not supported. You may get a linker error.
+codegen_gcc_invalid_minimum_alignment =
+ invalid minimum global alignment: {$err}
codegen_gcc_invalid_monomorphization_basic_integer =
invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
-codegen_gcc_invalid_monomorphization_invalid_float_vector =
- invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}`
-
-codegen_gcc_invalid_monomorphization_not_float =
- invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type
-
-codegen_gcc_invalid_monomorphization_unrecognized =
- invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
-
codegen_gcc_invalid_monomorphization_expected_signed_unsigned =
invalid monomorphization of `{$name}` intrinsic: expected element type `{$elem_ty}` of vector type `{$vec_ty}` to be a signed or unsigned integer type
-codegen_gcc_invalid_monomorphization_unsupported_element =
- invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}`
+codegen_gcc_invalid_monomorphization_expected_simd =
+ invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}`
+
+codegen_gcc_invalid_monomorphization_inserted_type =
+ invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
codegen_gcc_invalid_monomorphization_invalid_bitmask =
invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-codegen_gcc_invalid_monomorphization_simd_shuffle =
- invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
-
-codegen_gcc_invalid_monomorphization_expected_simd =
- invalid monomorphization of `{$name}` intrinsic: expected SIMD {$expected_ty} type, found non-SIMD `{$found_ty}`
+codegen_gcc_invalid_monomorphization_invalid_float_vector =
+ invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$elem_ty}` of floating-point vector `{$vec_ty}`
codegen_gcc_invalid_monomorphization_mask_type =
invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+codegen_gcc_invalid_monomorphization_mismatched_lengths =
+ invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+
+codegen_gcc_invalid_monomorphization_not_float =
+ invalid monomorphization of `{$name}` intrinsic: `{$ty}` is not a floating-point type
+
+codegen_gcc_invalid_monomorphization_return_element =
+ invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+
+codegen_gcc_invalid_monomorphization_return_integer_type =
+ invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+
codegen_gcc_invalid_monomorphization_return_length =
invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
codegen_gcc_invalid_monomorphization_return_length_input_type =
invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
-codegen_gcc_invalid_monomorphization_return_element =
- invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
-
codegen_gcc_invalid_monomorphization_return_type =
invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
-codegen_gcc_invalid_monomorphization_inserted_type =
- invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
-
-codegen_gcc_invalid_monomorphization_return_integer_type =
- invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+codegen_gcc_invalid_monomorphization_simd_shuffle =
+ invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
-codegen_gcc_invalid_monomorphization_mismatched_lengths =
- invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+codegen_gcc_invalid_monomorphization_unrecognized =
+ invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
codegen_gcc_invalid_monomorphization_unsupported_cast =
invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
+codegen_gcc_invalid_monomorphization_unsupported_element =
+ invalid monomorphization of `{$name}` intrinsic: unsupported {$name} from `{$in_ty}` with element `{$elem_ty}` to `{$ret_ty}`
+
codegen_gcc_invalid_monomorphization_unsupported_operation =
invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
-codegen_gcc_invalid_minimum_alignment =
- invalid minimum global alignment: {$err}
+codegen_gcc_lto_not_supported =
+ LTO is not supported. You may get a linker error.
codegen_gcc_tied_target_features = the target features {$features} must all be either enabled or disabled together
.help = add the missing features in a `target_feature` attribute
+
+codegen_gcc_unwinding_inline_asm =
+ GCC backend does not support unwinding from inline asm
diff --git a/compiler/rustc_codegen_gcc/src/allocator.rs b/compiler/rustc_codegen_gcc/src/allocator.rs
index 4bad33ee8..13f88192b 100644
--- a/compiler/rustc_codegen_gcc/src/allocator.rs
+++ b/compiler/rustc_codegen_gcc/src/allocator.rs
@@ -1,11 +1,13 @@
#[cfg(feature="master")]
use gccjit::FnAttribute;
use gccjit::{FunctionType, GlobalKind, ToRValue};
-use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_ast::expand::allocator::{
+ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
+ ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
+};
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::OomStrategy;
-use rustc_span::symbol::sym;
use crate::GccContext;
@@ -22,69 +24,71 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
let i8p = i8.make_pointer();
let void = context.new_type::<()>();
- for method in ALLOCATOR_METHODS {
- let mut types = Vec::with_capacity(method.inputs.len());
- for ty in method.inputs.iter() {
- match *ty {
- AllocatorTy::Layout => {
- types.push(usize);
- types.push(usize);
+ if kind == AllocatorKind::Default {
+ for method in ALLOCATOR_METHODS {
+ let mut types = Vec::with_capacity(method.inputs.len());
+ for ty in method.inputs.iter() {
+ match *ty {
+ AllocatorTy::Layout => {
+ types.push(usize);
+ types.push(usize);
+ }
+ AllocatorTy::Ptr => types.push(i8p),
+ AllocatorTy::Usize => types.push(usize),
+
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
}
- AllocatorTy::Ptr => types.push(i8p),
- AllocatorTy::Usize => types.push(usize),
-
- AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
}
- }
- let output = match method.output {
- AllocatorTy::ResultPtr => Some(i8p),
- AllocatorTy::Unit => None,
+ let output = match method.output {
+ AllocatorTy::ResultPtr => Some(i8p),
+ AllocatorTy::Unit => None,
- AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
- panic!("invalid allocator output")
- }
- };
- let name = format!("__rust_{}", method.name);
+ AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+ panic!("invalid allocator output")
+ }
+ };
+ let name = global_fn_name(method.name);
- let args: Vec<_> = types.iter().enumerate()
- .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
- .collect();
- let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let func = context.new_function(None, FunctionType::Exported, output.unwrap_or(void), &args, name, false);
- if tcx.sess.target.options.default_hidden_visibility {
+ if tcx.sess.target.options.default_hidden_visibility {
+ #[cfg(feature="master")]
+ func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+ }
+ if tcx.sess.must_emit_unwind_tables() {
+ // TODO(antoyo): emit unwind tables.
+ }
+
+ let callee = default_fn_name(method.name);
+ let args: Vec<_> = types.iter().enumerate()
+ .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
+ .collect();
+ let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
#[cfg(feature="master")]
- func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
- }
- if tcx.sess.must_emit_unwind_tables() {
- // TODO(antoyo): emit unwind tables.
- }
+ callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
+
+ let block = func.new_block("entry");
+
+ let args = args
+ .iter()
+ .enumerate()
+ .map(|(i, _)| func.get_param(i as i32).to_rvalue())
+ .collect::<Vec<_>>();
+ let ret = context.new_call(None, callee, &args);
+ //llvm::LLVMSetTailCall(ret, True);
+ if output.is_some() {
+ block.end_with_return(None, ret);
+ }
+ else {
+ block.end_with_void_return(None);
+ }
- let callee = kind.fn_name(method.name);
- let args: Vec<_> = types.iter().enumerate()
- .map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
- .collect();
- let callee = context.new_function(None, FunctionType::Extern, output.unwrap_or(void), &args, callee, false);
- #[cfg(feature="master")]
- callee.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
-
- let block = func.new_block("entry");
-
- let args = args
- .iter()
- .enumerate()
- .map(|(i, _)| func.get_param(i as i32).to_rvalue())
- .collect::<Vec<_>>();
- let ret = context.new_call(None, callee, &args);
- //llvm::LLVMSetTailCall(ret, True);
- if output.is_some() {
- block.end_with_return(None, ret);
- }
- else {
- block.end_with_void_return(None);
+ // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
+ // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
}
-
- // TODO(@Commeownist): Check if we need to emit some extra debugging info in certain circumstances
- // as described in https://github.com/rust-lang/rust/commit/77a96ed5646f7c3ee8897693decc4626fe380643
}
let types = [usize, usize];
@@ -99,7 +103,7 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
func.add_attribute(FnAttribute::Visibility(gccjit::Visibility::Hidden));
}
- let callee = alloc_error_handler_kind.fn_name(sym::oom);
+ let callee = alloc_error_handler_name(alloc_error_handler_kind);
let args: Vec<_> = types.iter().enumerate()
.map(|(index, typ)| context.new_parameter(None, *typ, &format!("param{}", index)))
.collect();
@@ -123,4 +127,9 @@ pub(crate) unsafe fn codegen(tcx: TyCtxt<'_>, mods: &mut GccContext, _module_nam
let value = tcx.sess.opts.unstable_opts.oom.should_panic();
let value = context.new_rvalue_from_int(i8, value as i32);
global.global_set_initializer_rvalue(value);
+
+ let name = NO_ALLOC_SHIM_IS_UNSTABLE.to_string();
+ let global = context.new_global(None, GlobalKind::Exported, i8, name);
+ let value = context.new_rvalue_from_int(i8, 0);
+ global.global_set_initializer_rvalue(value);
}
diff --git a/compiler/rustc_codegen_gcc/src/asm.rs b/compiler/rustc_codegen_gcc/src/asm.rs
index 65de02b35..250aa79f8 100644
--- a/compiler/rustc_codegen_gcc/src/asm.rs
+++ b/compiler/rustc_codegen_gcc/src/asm.rs
@@ -501,7 +501,7 @@ impl<'a, 'gcc, 'tcx> AsmBuilderMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
if options.contains(InlineAsmOptions::NORETURN) {
let builtin_unreachable = self.context.get_builtin_function("__builtin_unreachable");
let builtin_unreachable: RValue<'gcc> = unsafe { std::mem::transmute(builtin_unreachable) };
- self.call(self.type_void(), None, builtin_unreachable, &[], None);
+ self.call(self.type_void(), None, None, builtin_unreachable, &[], None);
}
// Write results to outputs.
@@ -593,6 +593,8 @@ fn reg_to_gcc(reg: InlineAsmRegOrRegClass) -> ConstraintOrRegister {
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w",
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => "a",
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => "d",
@@ -667,6 +669,8 @@ fn dummy_output_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, reg: InlineAsmRegCl
InlineAsmRegClass::Avr(_) => unimplemented!(),
InlineAsmRegClass::Bpf(_) => unimplemented!(),
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_addr) => cx.type_i32(),
InlineAsmRegClass::M68k(M68kInlineAsmRegClass::reg_data) => cx.type_i32(),
@@ -804,6 +808,7 @@ fn modifier_to_gcc(arch: InlineAsmArch, reg: InlineAsmRegClass, modifier: Option
}
}
InlineAsmRegClass::Hexagon(_) => None,
+ InlineAsmRegClass::LoongArch(_) => None,
InlineAsmRegClass::Mips(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::PowerPC(_) => None,
diff --git a/compiler/rustc_codegen_gcc/src/builder.rs b/compiler/rustc_codegen_gcc/src/builder.rs
index a3c8142be..869344ce9 100644
--- a/compiler/rustc_codegen_gcc/src/builder.rs
+++ b/compiler/rustc_codegen_gcc/src/builder.rs
@@ -35,6 +35,7 @@ use rustc_codegen_ssa::traits::{
};
use rustc_data_structures::fx::FxHashSet;
use rustc_middle::bug;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_middle::ty::layout::{FnAbiError, FnAbiOfHelpers, FnAbiRequest, HasParamEnv, HasTyCtxt, LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_span::Span;
@@ -455,12 +456,12 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
}
#[cfg(feature="master")]
- fn invoke(&mut self, typ: Type<'gcc>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: Option<&CodegenFnAttrs>, _fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
let try_block = self.current_func().new_block("try");
let current_block = self.block.clone();
self.block = try_block;
- let call = self.call(typ, None, func, args, None); // TODO(antoyo): use funclet here?
+ let call = self.call(typ, fn_attrs, None, func, args, None); // TODO(antoyo): use funclet here?
self.block = current_block;
let return_value = self.current_func()
@@ -483,8 +484,8 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
}
#[cfg(not(feature="master"))]
- fn invoke(&mut self, typ: Type<'gcc>, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
- let call_site = self.call(typ, None, func, args, None);
+ fn invoke(&mut self, typ: Type<'gcc>, fn_attrs: &CodegenFnAttrs, fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>, func: RValue<'gcc>, args: &[RValue<'gcc>], then: Block<'gcc>, catch: Block<'gcc>, _funclet: Option<&Funclet>) -> RValue<'gcc> {
+ let call_site = self.call(typ, fn_attrs, None, func, args, None);
let condition = self.context.new_rvalue_from_int(self.bool_type, 1);
self.llbb().end_with_conditional(None, condition, then, catch);
if let Some(_fn_abi) = fn_abi {
@@ -1226,6 +1227,11 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
(value1, value2)
}
+ fn filter_landing_pad(&mut self, pers_fn: RValue<'gcc>) -> (RValue<'gcc>, RValue<'gcc>) {
+ // TODO(antoyo): generate the correct landing pad
+ self.cleanup_landing_pad(pers_fn)
+ }
+
#[cfg(feature="master")]
fn resume(&mut self, exn0: RValue<'gcc>, _exn1: RValue<'gcc>) {
let exn_type = exn0.get_type();
@@ -1351,6 +1357,7 @@ impl<'a, 'gcc, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'gcc, 'tcx> {
fn call(
&mut self,
_typ: Type<'gcc>,
+ _fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
func: RValue<'gcc>,
args: &[RValue<'gcc>],
diff --git a/compiler/rustc_codegen_gcc/src/callee.rs b/compiler/rustc_codegen_gcc/src/callee.rs
index ba1e86562..433b2585f 100644
--- a/compiler/rustc_codegen_gcc/src/callee.rs
+++ b/compiler/rustc_codegen_gcc/src/callee.rs
@@ -17,7 +17,7 @@ use crate::context::CodegenCx;
pub fn get_fn<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, instance: Instance<'tcx>) -> Function<'gcc> {
let tcx = cx.tcx();
- assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_infer());
assert!(!instance.substs.has_escaping_bound_vars());
let sym = tcx.symbol_name(instance).name;
diff --git a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
index 94dc8c9e9..601768747 100644
--- a/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
+++ b/compiler/rustc_codegen_gcc/src/intrinsic/mod.rs
@@ -113,7 +113,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
_ if simple.is_some() => {
// FIXME(antoyo): remove this cast when the API supports function.
let func = unsafe { std::mem::transmute(simple.expect("simple")) };
- self.call(self.type_void(), None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
+ self.call(self.type_void(), None, None, func, &args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(), None)
},
sym::likely => {
self.expect(args[0].immediate(), true)
@@ -326,7 +326,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
let masked = self.and(addr, mask);
self.bitcast(masked, void_ptr_type)
},
-
+
_ if name_str.starts_with("simd_") => {
match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) {
Ok(llval) => llval,
@@ -354,7 +354,7 @@ impl<'a, 'gcc, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'a, 'gcc, 'tcx> {
fn abort(&mut self) {
let func = self.context.get_builtin_function("abort");
let func: RValue<'gcc> = unsafe { std::mem::transmute(func) };
- self.call(self.type_void(), None, func, &[], None);
+ self.call(self.type_void(), None, None, func, &[], None);
}
fn assume(&mut self, value: Self::Value) {
@@ -1135,7 +1135,7 @@ impl<'a, 'gcc, 'tcx> Builder<'a, 'gcc, 'tcx> {
fn try_intrinsic<'a, 'b, 'gcc, 'tcx>(bx: &'b mut Builder<'a, 'gcc, 'tcx>, try_func: RValue<'gcc>, data: RValue<'gcc>, _catch_func: RValue<'gcc>, dest: RValue<'gcc>) {
if bx.sess().panic_strategy() == PanicStrategy::Abort {
- bx.call(bx.type_void(), None, try_func, &[data], None);
+ bx.call(bx.type_void(), None, None, try_func, &[data], None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx.data_layout.i32_align.abi;
@@ -1204,21 +1204,21 @@ fn codegen_gnu_try<'gcc>(bx: &mut Builder<'_, 'gcc, '_>, try_func: RValue<'gcc>,
let zero = bx.cx.context.new_rvalue_zero(bx.int_type);
let ptr = bx.cx.context.new_call(None, eh_pointer_builtin, &[zero]);
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
- bx.call(catch_ty, None, catch_func, &[data, ptr], None);
+ bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
bx.ret(bx.const_i32(1));
// NOTE: the blocks must be filled before adding the try/catch, otherwise gcc will not
// generate a try/catch.
// FIXME(antoyo): add a check in the libgccjit API to prevent this.
bx.switch_to_block(current_block);
- bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
+ bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
});
let func = unsafe { std::mem::transmute(func) };
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llty, None, func, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, None, func, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs
index 0b661505a..442ce0ea5 100644
--- a/compiler/rustc_codegen_gcc/src/lib.rs
+++ b/compiler/rustc_codegen_gcc/src/lib.rs
@@ -27,6 +27,7 @@ extern crate rustc_attr;
extern crate rustc_codegen_ssa;
extern crate rustc_data_structures;
extern crate rustc_errors;
+extern crate rustc_fluent_macro;
extern crate rustc_hir;
extern crate rustc_macros;
extern crate rustc_metadata;
@@ -76,11 +77,11 @@ use rustc_codegen_ssa::target_features::supported_target_features;
use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ModuleBufferMethods, ThinBufferMethods, WriteBackendMethods};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
-use rustc_middle::ty::query::Providers;
use rustc_session::config::{Lto, OptLevel, OutputFilenames};
use rustc_session::Session;
use rustc_span::Symbol;
diff --git a/compiler/rustc_codegen_gcc/src/mono_item.rs b/compiler/rustc_codegen_gcc/src/mono_item.rs
index c1f634086..342b830ce 100644
--- a/compiler/rustc_codegen_gcc/src/mono_item.rs
+++ b/compiler/rustc_codegen_gcc/src/mono_item.rs
@@ -31,7 +31,7 @@ impl<'gcc, 'tcx> PreDefineMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
#[cfg_attr(not(feature="master"), allow(unused_variables))]
fn predefine_fn(&self, instance: Instance<'tcx>, linkage: Linkage, visibility: Visibility, symbol_name: &str) {
- assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_infer());
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
self.linkage.set(base::linkage_to_gcc(linkage));
diff --git a/compiler/rustc_codegen_gcc/src/type_.rs b/compiler/rustc_codegen_gcc/src/type_.rs
index daa661f35..521b64ad3 100644
--- a/compiler/rustc_codegen_gcc/src/type_.rs
+++ b/compiler/rustc_codegen_gcc/src/type_.rs
@@ -280,16 +280,4 @@ pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout
}
impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
- fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) {
- // Unsupported.
- }
-
- fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> {
- // Unsupported.
- self.context.new_rvalue_from_int(self.int_type, 0)
- }
-
- fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) {
- // Unsupported.
- }
}
diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml
index a7ba2f8b6..ad51f2d09 100644
--- a/compiler/rustc_codegen_llvm/Cargo.toml
+++ b/compiler/rustc_codegen_llvm/Cargo.toml
@@ -11,7 +11,7 @@ bitflags = "1.0"
cstr = "0.2"
libc = "0.2"
measureme = "10.0.0"
-object = { version = "0.30.1", default-features = false, features = [
+object = { version = "0.31.1", default-features = false, features = [
"std",
"read",
] }
@@ -22,6 +22,7 @@ rustc_attr = { path = "../rustc_attr" }
rustc_codegen_ssa = { path = "../rustc_codegen_ssa" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
@@ -35,6 +36,5 @@ rustc_target = { path = "../rustc_target" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
-tempfile = "3.2.0"
serde = { version = "1", features = [ "derive" ]}
serde_json = "1"
diff --git a/compiler/rustc_codegen_llvm/messages.ftl b/compiler/rustc_codegen_llvm/messages.ftl
index b6d7484bc..55622fdb2 100644
--- a/compiler/rustc_codegen_llvm/messages.ftl
+++ b/compiler/rustc_codegen_llvm/messages.ftl
@@ -1,90 +1,90 @@
-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_copy_bitcode = failed to copy bitcode to object file: {$err}
-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_dlltool_fail_import_library =
+ Dlltool could not create import library: {$stdout}
+ {$stderr}
+
+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_error_calling_dlltool =
+ Error calling dlltool '{$dlltool_path}': {$error}
codegen_llvm_error_creating_import_library =
Error creating import library for {$lib_name}: {$error}
-codegen_llvm_symbol_already_defined =
- symbol `{$symbol_name}` is already defined
+codegen_llvm_error_writing_def_file =
+ Error writing .DEF file: {$error}
+
+codegen_llvm_from_llvm_diag = {$message}
+codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name} ({$kind}): {$message}
codegen_llvm_invalid_minimum_alignment =
invalid minimum global alignment: {$err}
-codegen_llvm_sanitizer_memtag_requires_mte =
- `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
-
-codegen_llvm_error_writing_def_file =
- Error writing .DEF file: {$error}
+codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
+codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
-codegen_llvm_error_calling_dlltool =
- Error calling dlltool: {$error}
+codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
-codegen_llvm_dlltool_fail_import_library =
- Dlltool could not create import library: {$stdout}
- {$stderr}
+codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
-codegen_llvm_target_feature_disable_or_enable =
- the target features {$features} must all be either enabled or disabled together
+codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
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_multiple_source_dicompileunit = multiple source DICompileUnits found
+codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
+
+codegen_llvm_parse_bitcode = failed to parse bitcode for LTO module
+codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
codegen_llvm_parse_target_machine_config =
failed to parse target machine config to target machine: {$error}
-codegen_llvm_lto_disallowed = lto can only be run for executables, cdylibs and static library outputs
-
-codegen_llvm_lto_dylib = lto cannot be used for `dylib` crate type without `-Zdylib-lto`
-
-codegen_llvm_lto_bitcode_from_rlib = failed to get bitcode from object file for LTO ({$llvm_err})
-
-codegen_llvm_write_output = could not write output to {$path}
-codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
+codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
+codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
-codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
-codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
+codegen_llvm_prepare_thin_lto_module = failed to prepare thin LTO module
+codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
codegen_llvm_run_passes = failed to run LLVM passes
codegen_llvm_run_passes_with_llvm_err = failed to run LLVM passes: {$llvm_err}
+codegen_llvm_sanitizer_memtag_requires_mte =
+ `-Zsanitizer=memtag` requires `-Ctarget-feature=+mte`
+
codegen_llvm_serialize_module = failed to serialize module {$name}
codegen_llvm_serialize_module_with_llvm_err = failed to serialize module {$name}: {$llvm_err}
-codegen_llvm_write_ir = failed to write LLVM IR to {$path}
-codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err}
-
-codegen_llvm_prepare_thin_lto_context = failed to prepare thin LTO context
-codegen_llvm_prepare_thin_lto_context_with_llvm_err = failed to prepare thin LTO context: {$llvm_err}
+codegen_llvm_symbol_already_defined =
+ symbol `{$symbol_name}` is already defined
-codegen_llvm_load_bitcode = failed to load bitcode of module "{$name}"
-codegen_llvm_load_bitcode_with_llvm_err = failed to load bitcode of module "{$name}": {$llvm_err}
+codegen_llvm_target_feature_disable_or_enable =
+ the target features {$features} must all be either enabled or disabled together
-codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err}
-codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err}
+codegen_llvm_target_machine = could not create LLVM TargetMachine for triple: {$triple}
+codegen_llvm_target_machine_with_llvm_err = could not create LLVM TargetMachine for triple: {$triple}: {$llvm_err}
-codegen_llvm_multiple_source_dicompileunit = multiple source DICompileUnits found
-codegen_llvm_multiple_source_dicompileunit_with_llvm_err = multiple source DICompileUnits found: {$llvm_err}
+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_prepare_thin_lto_module = failed to prepare thin LTO module
-codegen_llvm_prepare_thin_lto_module_with_llvm_err = failed to prepare thin LTO module: {$llvm_err}
+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_parse_bitcode = failed to parse bitcode for LTO module
-codegen_llvm_parse_bitcode_with_llvm_err = failed to parse bitcode for LTO module: {$llvm_err}
+codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
-codegen_llvm_from_llvm_optimization_diag = {$filename}:{$line}:{$column} {$pass_name}: {$message}
-codegen_llvm_from_llvm_diag = {$message}
+codegen_llvm_write_ir = failed to write LLVM IR to {$path}
+codegen_llvm_write_ir_with_llvm_err = failed to write LLVM IR to {$path}: {$llvm_err}
-codegen_llvm_write_bytecode = failed to write bytecode to {$path}: {$err}
+codegen_llvm_write_output = could not write output to {$path}
+codegen_llvm_write_output_with_llvm_err = could not write output to {$path}: {$llvm_err}
-codegen_llvm_copy_bitcode = failed to copy bitcode to object file: {$err}
+codegen_llvm_write_thinlto_key = error while writing ThinLTO key data: {$err}
+codegen_llvm_write_thinlto_key_with_llvm_err = error while writing ThinLTO key data: {$err}: {$llvm_err}
diff --git a/compiler/rustc_codegen_llvm/src/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs
index 668d92927..a57508815 100644
--- a/compiler/rustc_codegen_llvm/src/allocator.rs
+++ b/compiler/rustc_codegen_llvm/src/allocator.rs
@@ -1,10 +1,12 @@
use crate::attributes;
use libc::c_uint;
-use rustc_ast::expand::allocator::{AllocatorKind, AllocatorTy, ALLOCATOR_METHODS};
+use rustc_ast::expand::allocator::{
+ alloc_error_handler_name, default_fn_name, global_fn_name, AllocatorKind, AllocatorTy,
+ ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE,
+};
use rustc_middle::bug;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{DebugInfo, OomStrategy};
-use rustc_span::symbol::sym;
use crate::debuginfo;
use crate::llvm::{self, False, True};
@@ -29,75 +31,78 @@ pub(crate) unsafe fn codegen(
let i8p = llvm::LLVMPointerType(i8, 0);
let void = llvm::LLVMVoidTypeInContext(llcx);
- for method in ALLOCATOR_METHODS {
- let mut args = Vec::with_capacity(method.inputs.len());
- for ty in method.inputs.iter() {
- match *ty {
- AllocatorTy::Layout => {
- args.push(usize); // size
- args.push(usize); // align
+ if kind == AllocatorKind::Default {
+ for method in ALLOCATOR_METHODS {
+ let mut args = Vec::with_capacity(method.inputs.len());
+ for ty in method.inputs.iter() {
+ match *ty {
+ AllocatorTy::Layout => {
+ args.push(usize); // size
+ args.push(usize); // align
+ }
+ AllocatorTy::Ptr => args.push(i8p),
+ AllocatorTy::Usize => args.push(usize),
+
+ AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
}
- AllocatorTy::Ptr => args.push(i8p),
- AllocatorTy::Usize => args.push(usize),
-
- AllocatorTy::ResultPtr | AllocatorTy::Unit => panic!("invalid allocator arg"),
}
- }
- let output = match method.output {
- AllocatorTy::ResultPtr => Some(i8p),
- AllocatorTy::Unit => None,
+ let output = match method.output {
+ AllocatorTy::ResultPtr => Some(i8p),
+ AllocatorTy::Unit => None,
- AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
- panic!("invalid allocator output")
+ AllocatorTy::Layout | AllocatorTy::Usize | AllocatorTy::Ptr => {
+ panic!("invalid allocator output")
+ }
+ };
+ let ty = llvm::LLVMFunctionType(
+ output.unwrap_or(void),
+ args.as_ptr(),
+ args.len() as c_uint,
+ False,
+ );
+ let name = global_fn_name(method.name);
+ let llfn =
+ llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
+
+ if tcx.sess.target.default_hidden_visibility {
+ llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
+ }
+ if tcx.sess.must_emit_unwind_tables() {
+ let uwtable = attributes::uwtable_attr(llcx);
+ attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
}
- };
- let ty = llvm::LLVMFunctionType(
- output.unwrap_or(void),
- args.as_ptr(),
- args.len() as c_uint,
- False,
- );
- let name = format!("__rust_{}", method.name);
- let llfn = llvm::LLVMRustGetOrInsertFunction(llmod, name.as_ptr().cast(), name.len(), ty);
-
- if tcx.sess.target.default_hidden_visibility {
- llvm::LLVMRustSetVisibility(llfn, llvm::Visibility::Hidden);
- }
- if tcx.sess.must_emit_unwind_tables() {
- let uwtable = attributes::uwtable_attr(llcx);
- attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
- }
- let callee = kind.fn_name(method.name);
- let callee =
- llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
- llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
-
- let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
-
- let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
- llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
- let args = args
- .iter()
- .enumerate()
- .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
- .collect::<Vec<_>>();
- let ret = llvm::LLVMRustBuildCall(
- llbuilder,
- ty,
- callee,
- args.as_ptr(),
- args.len() as c_uint,
- [].as_ptr(),
- 0 as c_uint,
- );
- llvm::LLVMSetTailCall(ret, True);
- if output.is_some() {
- llvm::LLVMBuildRet(llbuilder, ret);
- } else {
- llvm::LLVMBuildRetVoid(llbuilder);
+ let callee = default_fn_name(method.name);
+ let callee =
+ llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
+ llvm::LLVMRustSetVisibility(callee, llvm::Visibility::Hidden);
+
+ let llbb = llvm::LLVMAppendBasicBlockInContext(llcx, llfn, "entry\0".as_ptr().cast());
+
+ let llbuilder = llvm::LLVMCreateBuilderInContext(llcx);
+ llvm::LLVMPositionBuilderAtEnd(llbuilder, llbb);
+ let args = args
+ .iter()
+ .enumerate()
+ .map(|(i, _)| llvm::LLVMGetParam(llfn, i as c_uint))
+ .collect::<Vec<_>>();
+ let ret = llvm::LLVMRustBuildCall(
+ llbuilder,
+ ty,
+ callee,
+ args.as_ptr(),
+ args.len() as c_uint,
+ [].as_ptr(),
+ 0 as c_uint,
+ );
+ llvm::LLVMSetTailCall(ret, True);
+ if output.is_some() {
+ llvm::LLVMBuildRet(llbuilder, ret);
+ } else {
+ llvm::LLVMBuildRetVoid(llbuilder);
+ }
+ llvm::LLVMDisposeBuilder(llbuilder);
}
- llvm::LLVMDisposeBuilder(llbuilder);
}
// rust alloc error handler
@@ -118,7 +123,7 @@ pub(crate) unsafe fn codegen(
attributes::apply_to_llfn(llfn, llvm::AttributePlace::Function, &[uwtable]);
}
- let callee = alloc_error_handler_kind.fn_name(sym::oom);
+ let callee = alloc_error_handler_name(alloc_error_handler_kind);
let callee = llvm::LLVMRustGetOrInsertFunction(llmod, callee.as_ptr().cast(), callee.len(), ty);
// -> ! DIFlagNoReturn
attributes::apply_to_llfn(callee, llvm::AttributePlace::Function, &[no_return]);
@@ -156,6 +161,14 @@ pub(crate) unsafe fn codegen(
let llval = llvm::LLVMConstInt(i8, val as u64, False);
llvm::LLVMSetInitializer(ll_g, llval);
+ let name = NO_ALLOC_SHIM_IS_UNSTABLE;
+ let ll_g = llvm::LLVMRustGetOrInsertGlobal(llmod, name.as_ptr().cast(), name.len(), i8);
+ if tcx.sess.target.default_hidden_visibility {
+ llvm::LLVMRustSetVisibility(ll_g, llvm::Visibility::Hidden);
+ }
+ let llval = llvm::LLVMConstInt(i8, 0, False);
+ llvm::LLVMSetInitializer(ll_g, llval);
+
if tcx.sess.opts.debuginfo != DebugInfo::None {
let dbg_cx = debuginfo::CodegenUnitDebugContext::new(llmod);
debuginfo::metadata::build_compile_unit_di_node(tcx, module_name, &dbg_cx);
diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs
index 1a3865360..2a6ad1be7 100644
--- a/compiler/rustc_codegen_llvm/src/asm.rs
+++ b/compiler/rustc_codegen_llvm/src/asm.rs
@@ -236,8 +236,22 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> {
InlineAsmArch::Nvptx64 => {}
InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => {}
InlineAsmArch::Hexagon => {}
+ InlineAsmArch::LoongArch64 => {
+ constraints.extend_from_slice(&[
+ "~{$fcc0}".to_string(),
+ "~{$fcc1}".to_string(),
+ "~{$fcc2}".to_string(),
+ "~{$fcc3}".to_string(),
+ "~{$fcc4}".to_string(),
+ "~{$fcc5}".to_string(),
+ "~{$fcc6}".to_string(),
+ "~{$fcc7}".to_string(),
+ ]);
+ }
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {}
- InlineAsmArch::S390x => {}
+ InlineAsmArch::S390x => {
+ constraints.push("~{cc}".to_string());
+ }
InlineAsmArch::SpirV => {}
InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {}
InlineAsmArch::Bpf => {}
@@ -442,9 +456,9 @@ pub(crate) fn inline_asm_call<'ll>(
);
let call = if let Some((dest, catch, funclet)) = dest_catch_funclet {
- bx.invoke(fty, None, v, inputs, dest, catch, funclet)
+ bx.invoke(fty, None, None, v, inputs, dest, catch, funclet)
} else {
- bx.call(fty, None, v, inputs, None)
+ bx.call(fty, None, None, v, inputs, None)
};
// Store mark in a metadata node so we can map LLVM errors
@@ -633,6 +647,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg)
| InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w",
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => "r",
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r",
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f",
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h",
@@ -719,6 +735,7 @@ fn modifier_to_llvm(
}
}
InlineAsmRegClass::Hexagon(_) => None,
+ InlineAsmRegClass::LoongArch(_) => None,
InlineAsmRegClass::Mips(_) => None,
InlineAsmRegClass::Nvptx(_) => None,
InlineAsmRegClass::PowerPC(_) => None,
@@ -803,6 +820,8 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &'
cx.type_vector(cx.type_i64(), 2)
}
InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::reg) => cx.type_i32(),
+ InlineAsmRegClass::LoongArch(LoongArchInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => cx.type_i32(),
InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => cx.type_f32(),
InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => cx.type_i16(),
diff --git a/compiler/rustc_codegen_llvm/src/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs
index 12da21dc4..a6416e954 100644
--- a/compiler/rustc_codegen_llvm/src/back/archive.rs
+++ b/compiler/rustc_codegen_llvm/src/back/archive.rs
@@ -198,7 +198,7 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
"arm" => ("arm", "--32"),
_ => panic!("unsupported arch {}", sess.target.arch),
};
- let result = std::process::Command::new(dlltool)
+ let result = std::process::Command::new(&dlltool)
.args([
"-d",
def_file_path.to_str().unwrap(),
@@ -218,9 +218,13 @@ impl ArchiveBuilderBuilder for LlvmArchiveBuilderBuilder {
match result {
Err(e) => {
- sess.emit_fatal(ErrorCallingDllTool { error: e });
+ sess.emit_fatal(ErrorCallingDllTool {
+ dlltool_path: dlltool.to_string_lossy(),
+ error: e,
+ });
}
- Ok(output) if !output.status.success() => {
+ // dlltool returns '0' on failure, so check for error output instead.
+ Ok(output) if !output.stderr.is_empty() => {
sess.emit_fatal(DlltoolFailImportLibrary {
stdout: String::from_utf8_lossy(&output.stdout),
stderr: String::from_utf8_lossy(&output.stderr),
@@ -431,7 +435,7 @@ fn string_to_io_error(s: String) -> io::Error {
fn find_binutils_dlltool(sess: &Session) -> OsString {
assert!(sess.target.options.is_like_windows && !sess.target.options.is_like_msvc);
- if let Some(dlltool_path) = &sess.opts.unstable_opts.dlltool {
+ if let Some(dlltool_path) = &sess.opts.cg.dlltool {
return dlltool_path.clone().into_os_string();
}
diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs
index d2e01708a..604f68eb6 100644
--- a/compiler/rustc_codegen_llvm/src/back/lto.rs
+++ b/compiler/rustc_codegen_llvm/src/back/lto.rs
@@ -25,7 +25,6 @@ use std::fs::File;
use std::io;
use std::iter;
use std::path::Path;
-use std::ptr;
use std::slice;
use std::sync::Arc;
@@ -709,17 +708,6 @@ pub unsafe fn optimize_thin_module(
let llmod = module.module_llvm.llmod();
save_temp_bitcode(cgcx, &module, "thin-lto-input");
- // Before we do much else find the "main" `DICompileUnit` that we'll be
- // using below. If we find more than one though then rustc has changed
- // in a way we're not ready for, so generate an ICE by returning
- // an error.
- let mut cu1 = ptr::null_mut();
- let mut cu2 = ptr::null_mut();
- llvm::LLVMRustThinLTOGetDICompileUnit(llmod, &mut cu1, &mut cu2);
- if !cu2.is_null() {
- return Err(write::llvm_err(&diag_handler, LlvmError::MultipleSourceDiCompileUnit));
- }
-
// Up next comes the per-module local analyses that we do for Thin LTO.
// Each of these functions is basically copied from the LLVM
// implementation and then tailored to suit this implementation. Ideally
@@ -766,43 +754,6 @@ pub unsafe fn optimize_thin_module(
save_temp_bitcode(cgcx, &module, "thin-lto-after-import");
}
- // Ok now this is a bit unfortunate. This is also something you won't
- // find upstream in LLVM's ThinLTO passes! This is a hack for now to
- // work around bugs in LLVM.
- //
- // First discovered in #45511 it was found that as part of ThinLTO
- // importing passes LLVM will import `DICompileUnit` metadata
- // information across modules. This means that we'll be working with one
- // LLVM module that has multiple `DICompileUnit` instances in it (a
- // bunch of `llvm.dbg.cu` members). Unfortunately there's a number of
- // bugs in LLVM's backend which generates invalid DWARF in a situation
- // like this:
- //
- // https://bugs.llvm.org/show_bug.cgi?id=35212
- // https://bugs.llvm.org/show_bug.cgi?id=35562
- //
- // While the first bug there is fixed the second ended up causing #46346
- // which was basically a resurgence of #45511 after LLVM's bug 35212 was
- // fixed.
- //
- // This function below is a huge hack around this problem. The function
- // below is defined in `PassWrapper.cpp` and will basically "merge"
- // all `DICompileUnit` instances in a module. Basically it'll take all
- // the objects, rewrite all pointers of `DISubprogram` to point to the
- // first `DICompileUnit`, and then delete all the other units.
- //
- // This is probably mangling to the debug info slightly (but hopefully
- // not too much) but for now at least gets LLVM to emit valid DWARF (or
- // so it appears). Hopefully we can remove this once upstream bugs are
- // fixed in LLVM.
- {
- let _timer = cgcx
- .prof
- .generic_activity_with_arg("LLVM_thin_lto_patch_debuginfo", thin_module.name());
- llvm::LLVMRustThinLTOPatchDICompileUnit(llmod, cu1);
- save_temp_bitcode(cgcx, &module, "thin-lto-after-patch");
- }
-
// Alright now that we've done everything related to the ThinLTO
// analysis it's time to run some optimizations! Here we use the same
// `run_pass_manager` as the "fat" LTO above except that we tell it to
diff --git a/compiler/rustc_codegen_llvm/src/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs
index 7136f750f..ca2eab28f 100644
--- a/compiler/rustc_codegen_llvm/src/back/write.rs
+++ b/compiler/rustc_codegen_llvm/src/back/write.rs
@@ -31,6 +31,7 @@ use rustc_span::symbol::sym;
use rustc_span::InnerSpan;
use rustc_target::spec::{CodeModel, RelocModel, SanitizerSet, SplitDebuginfo};
+use crate::llvm::diagnostic::OptimizationDiagnosticKind;
use libc::{c_char, c_int, c_uint, c_void, size_t};
use std::ffi::CString;
use std::fs;
@@ -363,6 +364,15 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void
line: opt.line,
column: opt.column,
pass_name: &opt.pass_name,
+ kind: match opt.kind {
+ OptimizationDiagnosticKind::OptimizationRemark => "success",
+ OptimizationDiagnosticKind::OptimizationMissed
+ | OptimizationDiagnosticKind::OptimizationFailure => "missed",
+ OptimizationDiagnosticKind::OptimizationAnalysis
+ | OptimizationDiagnosticKind::OptimizationAnalysisFPCommute
+ | OptimizationDiagnosticKind::OptimizationAnalysisAliasing => "analysis",
+ OptimizationDiagnosticKind::OptimizationRemarkOther => "other",
+ },
message: &opt.message,
});
}
diff --git a/compiler/rustc_codegen_llvm/src/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs
index 6819a2af0..4d0bcd53d 100644
--- a/compiler/rustc_codegen_llvm/src/builder.rs
+++ b/compiler/rustc_codegen_llvm/src/builder.rs
@@ -15,14 +15,15 @@ use rustc_codegen_ssa::traits::*;
use rustc_codegen_ssa::MemFlags;
use rustc_data_structures::small_c_str::SmallCStr;
use rustc_hir::def_id::DefId;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{
FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOfHelpers, TyAndLayout,
};
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::Span;
-use rustc_symbol_mangling::typeid::kcfi_typeid_for_fnabi;
+use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi, TypeIdOptions};
use rustc_target::abi::{self, call::FnAbi, Align, Size, WrappingRange};
-use rustc_target::spec::{HasTargetSpec, Target};
+use rustc_target::spec::{HasTargetSpec, SanitizerSet, Target};
use std::borrow::Cow;
use std::ffi::CStr;
use std::iter;
@@ -216,6 +217,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn invoke(
&mut self,
llty: &'ll Type,
+ fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: &'ll Value,
args: &[&'ll Value],
@@ -230,19 +232,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
let mut bundles = vec![funclet_bundle];
- // Set KCFI operand bundle
- let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
- let kcfi_bundle =
- if self.tcx.sess.is_sanitizer_kcfi_enabled() && let Some(fn_abi) = fn_abi && is_indirect_call {
- let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
- Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
- } else {
- None
- };
- if kcfi_bundle.is_some() {
- let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
- bundles.push(kcfi_bundle);
- }
+ // Emit CFI pointer type membership test
+ self.cfi_type_test(fn_attrs, fn_abi, llfn);
+
+ // Emit KCFI operand bundle
+ let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
+ let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
+ bundles.push(kcfi_bundle);
bundles.retain(|bundle| bundle.is_some());
let invoke = unsafe {
@@ -989,13 +985,20 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn cleanup_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
- let landing_pad = self.landing_pad(ty, pers_fn, 1 /* FIXME should this be 0? */);
+ let landing_pad = self.landing_pad(ty, pers_fn, 0);
unsafe {
llvm::LLVMSetCleanup(landing_pad, llvm::True);
}
(self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
}
+ fn filter_landing_pad(&mut self, pers_fn: &'ll Value) -> (&'ll Value, &'ll Value) {
+ let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
+ let landing_pad = self.landing_pad(ty, pers_fn, 1);
+ self.add_clause(landing_pad, self.const_array(self.type_i8p(), &[]));
+ (self.extract_value(landing_pad, 0), self.extract_value(landing_pad, 1))
+ }
+
fn resume(&mut self, exn0: &'ll Value, exn1: &'ll Value) {
let ty = self.type_struct(&[self.type_i8p(), self.type_i32()], false);
let mut exn = self.const_poison(ty);
@@ -1183,6 +1186,7 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
fn call(
&mut self,
llty: &'ll Type,
+ fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: &'ll Value,
args: &[&'ll Value],
@@ -1195,19 +1199,13 @@ impl<'a, 'll, 'tcx> BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> {
let funclet_bundle = funclet_bundle.as_ref().map(|b| &*b.raw);
let mut bundles = vec![funclet_bundle];
- // Set KCFI operand bundle
- let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
- let kcfi_bundle =
- if let Some(fn_abi) = fn_abi && self.tcx.sess.is_sanitizer_kcfi_enabled() && is_indirect_call {
- let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
- Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
- } else {
- None
- };
- if kcfi_bundle.is_some() {
- let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
- bundles.push(kcfi_bundle);
- }
+ // Emit CFI pointer type membership test
+ self.cfi_type_test(fn_attrs, fn_abi, llfn);
+
+ // Emit KCFI operand bundle
+ let kcfi_bundle = self.kcfi_operand_bundle(fn_attrs, fn_abi, llfn);
+ let kcfi_bundle = kcfi_bundle.as_ref().map(|b| &*b.raw);
+ bundles.push(kcfi_bundle);
bundles.retain(|bundle| bundle.is_some());
let call = unsafe {
@@ -1456,7 +1454,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
pub(crate) fn call_intrinsic(&mut self, intrinsic: &str, args: &[&'ll Value]) -> &'ll Value {
let (ty, f) = self.cx.get_intrinsic(intrinsic);
- self.call(ty, None, f, args, None)
+ self.call(ty, None, None, f, args, None)
}
fn call_lifetime_intrinsic(&mut self, intrinsic: &str, ptr: &'ll Value, size: Size) {
@@ -1518,7 +1516,7 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
format!("llvm.{}.sat.i{}.f{}", instr, int_width, float_width)
};
let f = self.declare_cfn(&name, llvm::UnnamedAddr::No, self.type_func(&[src_ty], dest_ty));
- self.call(self.type_func(&[src_ty], dest_ty), None, f, &[val], None)
+ self.call(self.type_func(&[src_ty], dest_ty), None, None, f, &[val], None)
}
pub(crate) fn landing_pad(
@@ -1535,4 +1533,71 @@ impl<'a, 'll, 'tcx> Builder<'a, 'll, 'tcx> {
llvm::LLVMBuildLandingPad(self.llbuilder, ty, None, num_clauses as c_uint, UNNAMED)
}
}
+
+ // Emits CFI pointer type membership tests.
+ fn cfi_type_test(
+ &mut self,
+ fn_attrs: Option<&CodegenFnAttrs>,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ llfn: &'ll Value,
+ ) {
+ let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
+ if is_indirect_call && fn_abi.is_some() && self.tcx.sess.is_sanitizer_cfi_enabled() {
+ if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::CFI) {
+ return;
+ }
+
+ let mut options = TypeIdOptions::empty();
+ if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+ }
+ if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+ }
+
+ let typeid = typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
+ let typeid_metadata = self.cx.typeid_metadata(typeid).unwrap();
+
+ // Test whether the function pointer is associated with the type identifier.
+ let cond = self.type_test(llfn, typeid_metadata);
+ let bb_pass = self.append_sibling_block("type_test.pass");
+ let bb_fail = self.append_sibling_block("type_test.fail");
+ self.cond_br(cond, bb_pass, bb_fail);
+
+ self.switch_to_block(bb_fail);
+ self.abort();
+ self.unreachable();
+
+ self.switch_to_block(bb_pass);
+ }
+ }
+
+ // Emits KCFI operand bundles.
+ fn kcfi_operand_bundle(
+ &mut self,
+ fn_attrs: Option<&CodegenFnAttrs>,
+ fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
+ llfn: &'ll Value,
+ ) -> Option<llvm::OperandBundleDef<'ll>> {
+ let is_indirect_call = unsafe { llvm::LLVMIsAFunction(llfn).is_none() };
+ let kcfi_bundle = if is_indirect_call && self.tcx.sess.is_sanitizer_kcfi_enabled() {
+ if fn_attrs.is_some() && fn_attrs.unwrap().no_sanitize.contains(SanitizerSet::KCFI) {
+ return None;
+ }
+
+ let mut options = TypeIdOptions::empty();
+ if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+ }
+ if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+ }
+
+ let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi.unwrap(), options);
+ Some(llvm::OperandBundleDef::new("kcfi", &[self.const_u32(kcfi_typeid)]))
+ } else {
+ None
+ };
+ kcfi_bundle
+ }
}
diff --git a/compiler/rustc_codegen_llvm/src/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs
index 6ee2a05ff..4b9ca2e7d 100644
--- a/compiler/rustc_codegen_llvm/src/callee.rs
+++ b/compiler/rustc_codegen_llvm/src/callee.rs
@@ -27,7 +27,7 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
debug!("get_fn(instance={:?})", instance);
- assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_infer());
assert!(!instance.substs.has_escaping_bound_vars());
if let Some(&llfn) = cx.instances.borrow().get(&instance) {
@@ -94,11 +94,11 @@ pub fn get_fn<'ll, 'tcx>(cx: &CodegenCx<'ll, 'tcx>, instance: Instance<'tcx>) ->
// LLVM will prefix the name with `__imp_`. Ideally, we'd like the
// existing logic below to set the Storage Class, but it has an
// exemption for MinGW for backwards compatability.
- let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi);
+ let llfn = cx.declare_fn(&common::i686_decorated_name(&dllimport, common::is_mingw_gnu_toolchain(&tcx.sess.target), true), fn_abi, Some(instance));
unsafe { llvm::LLVMSetDLLStorageClass(llfn, llvm::DLLStorageClass::DllImport); }
llfn
} else {
- cx.declare_fn(sym, fn_abi)
+ cx.declare_fn(sym, fn_abi, Some(instance))
};
debug!("get_fn: not casting pointer!");
diff --git a/compiler/rustc_codegen_llvm/src/common.rs b/compiler/rustc_codegen_llvm/src/common.rs
index 4f8b5abd9..9127fba38 100644
--- a/compiler/rustc_codegen_llvm/src/common.rs
+++ b/compiler/rustc_codegen_llvm/src/common.rs
@@ -10,7 +10,7 @@ use crate::value::Value;
use rustc_ast::Mutability;
use rustc_codegen_ssa::mir::place::PlaceRef;
use rustc_codegen_ssa::traits::*;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
use rustc_hir::def_id::DefId;
use rustc_middle::bug;
use rustc_middle::mir::interpret::{ConstAllocation, GlobalAlloc, Scalar};
@@ -261,7 +261,7 @@ impl<'ll, 'tcx> ConstMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let hash = self.tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new();
alloc.hash_stable(&mut hcx, &mut hasher);
- hasher.finish::<u128>()
+ hasher.finish::<Hash128>()
});
llvm::set_value_name(value, format!("alloc_{hash:032x}").as_bytes());
}
diff --git a/compiler/rustc_codegen_llvm/src/context.rs b/compiler/rustc_codegen_llvm/src/context.rs
index f0d729d47..83101a854 100644
--- a/compiler/rustc_codegen_llvm/src/context.rs
+++ b/compiler/rustc_codegen_llvm/src/context.rs
@@ -228,18 +228,29 @@ pub unsafe fn create_module<'ll>(
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Warning, avoid_plt, 1);
}
- if sess.is_sanitizer_cfi_enabled() {
- // FIXME(rcvalle): Add support for non canonical jump tables.
+ // Enable canonical jump tables if CFI is enabled. (See https://reviews.llvm.org/D65629.)
+ if sess.is_sanitizer_cfi_canonical_jump_tables_enabled() && sess.is_sanitizer_cfi_enabled() {
let canonical_jump_tables = "CFI Canonical Jump Tables\0".as_ptr().cast();
- // FIXME(rcvalle): Add it with Override behavior flag.
llvm::LLVMRustAddModuleFlag(
llmod,
- llvm::LLVMModFlagBehavior::Warning,
+ llvm::LLVMModFlagBehavior::Override,
canonical_jump_tables,
1,
);
}
+ // Enable LTO unit splitting if specified or if CFI is enabled. (See https://reviews.llvm.org/D53891.)
+ if sess.is_split_lto_unit_enabled() || sess.is_sanitizer_cfi_enabled() {
+ let enable_split_lto_unit = "EnableSplitLTOUnit\0".as_ptr().cast();
+ llvm::LLVMRustAddModuleFlag(
+ llmod,
+ llvm::LLVMModFlagBehavior::Override,
+ enable_split_lto_unit,
+ 1,
+ );
+ }
+
+ // Add "kcfi" module flag if KCFI is enabled. (See https://reviews.llvm.org/D119296.)
if sess.is_sanitizer_kcfi_enabled() {
let kcfi = "kcfi\0".as_ptr().cast();
llvm::LLVMRustAddModuleFlag(llmod, llvm::LLVMModFlagBehavior::Override, kcfi, 1);
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
index 240a9d2f3..21a1ac348 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs
@@ -163,7 +163,7 @@ impl CoverageMapGenerator {
counter_regions.sort_unstable_by_key(|(_counter, region)| *region);
for (counter, region) in counter_regions {
let CodeRegion { file_name, start_line, start_col, end_line, end_col } = *region;
- let same_file = current_file_name.map_or(false, |p| p == file_name);
+ let same_file = current_file_name.is_some_and(|p| p == file_name);
if !same_file {
if current_file_name.is_some() {
current_file_id += 1;
diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
index 3dc0ac033..cd261293e 100644
--- a/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs
@@ -207,6 +207,7 @@ fn declare_unused_fn<'tcx>(cx: &CodegenCx<'_, 'tcx>, def_id: DefId) -> Instance<
)),
ty::List::empty(),
),
+ None,
);
llvm::set_linkage(llfn, llvm::Linkage::PrivateLinkage);
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
index 99e4ded62..3fff112a0 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs
@@ -12,7 +12,7 @@ use rustc_middle::ty::{self, Instance};
use rustc_session::config::DebugInfo;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
/// Produces DIScope DIEs for each MIR Scope which has variables defined in it.
// FIXME(eddyb) almost all of this should be in `rustc_codegen_ssa::mir::debuginfo`.
@@ -93,7 +93,7 @@ fn make_mir_scope<'ll, 'tcx>(
let callee = cx.tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
- callee,
+ ty::EarlyBinder(callee),
);
let callee_fn_abi = cx.fn_abi_of_instance(callee, ty::List::empty());
cx.dbg_scope_fn(callee, callee_fn_abi, None)
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
index ff2b005d7..37f309176 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs
@@ -9,10 +9,9 @@ use rustc_ast::attr;
use rustc_codegen_ssa::base::collect_debugger_visualizers_transitive;
use rustc_codegen_ssa::traits::*;
use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::bug;
+use rustc_middle::{bug, middle::debugger_visualizer::DebuggerVisualizerType};
use rustc_session::config::{CrateType, DebugInfo};
use rustc_span::symbol::sym;
-use rustc_span::DebuggerVisualizerType;
/// Inserts a side-effect free instruction sequence that makes sure that the
/// .debug_gdb_scripts global is referenced, so it isn't removed by the linker.
@@ -22,9 +21,9 @@ pub fn insert_reference_to_gdb_debug_scripts_section_global(bx: &mut Builder<'_,
bx.const_bitcast(get_or_insert_gdb_debug_scripts_section_global(bx), bx.type_i8p());
// Load just the first byte as that's all that's necessary to force
// LLVM to keep around the reference to the global.
- let volative_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
+ let volatile_load_instruction = bx.volatile_load(bx.type_i8(), gdb_debug_scripts_section);
unsafe {
- llvm::LLVMSetAlignment(volative_load_instruction, 1);
+ llvm::LLVMSetAlignment(volatile_load_instruction, 1);
}
}
}
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
index 21a0a60b0..bd2fba126 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs
@@ -29,7 +29,6 @@ use rustc_hir::def::CtorKind;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::bug;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
-use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{
self, AdtKind, Instance, ParamEnv, PolyExistentialTraitRef, Ty, TyCtxt, Visibility,
};
@@ -807,8 +806,7 @@ pub fn build_compile_unit_di_node<'ll, 'tcx>(
name_in_debuginfo.push(codegen_unit_name);
debug!("build_compile_unit_di_node: {:?}", name_in_debuginfo);
- let rustc_producer =
- format!("rustc version {}", option_env!("CFG_VERSION").expect("CFG_VERSION"),);
+ let rustc_producer = format!("rustc version {}", tcx.sess.cfg_version);
// FIXME(#41252) Remove "clang LLVM" if we can get GDB and LLVM to play nice.
let producer = format!("clang LLVM ({})", rustc_producer);
@@ -1182,12 +1180,12 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
let names = get_parameter_names(cx, generics);
let template_params: SmallVec<_> = iter::zip(substs, names)
.filter_map(|(kind, name)| {
- if let GenericArgKind::Type(ty) = kind.unpack() {
+ kind.as_type().map(|ty| {
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_di_node = type_di_node(cx, actual_type);
let name = name.as_str();
- Some(unsafe {
+ unsafe {
llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
@@ -1195,10 +1193,8 @@ fn build_generic_type_param_di_nodes<'ll, 'tcx>(
name.len(),
actual_type_di_node,
)
- })
- } else {
- None
- }
+ }
+ })
})
.collect();
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
index 69443b9b8..ecb0912d3 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/cpp_like.rs
@@ -6,7 +6,7 @@ use rustc_codegen_ssa::{
traits::ConstMethods,
};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::{
bug,
ty::{
@@ -62,7 +62,7 @@ const SINGLE_VARIANT_VIRTUAL_DISR: u64 = 0;
/// In CPP-like mode, we generate a union with a field for each variant and an
/// explicit tag field. The field of each variant has a struct type
-/// that encodes the discrimiant of the variant and it's data layout.
+/// that encodes the discriminant of the variant and it's data layout.
/// The union also has a nested enumeration type that is only used for encoding
/// variant names in an efficient way. Its enumerator values do _not_ correspond
/// to the enum's discriminant values.
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
index 55a217f59..9e0e847a1 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata/enums/mod.rs
@@ -3,7 +3,7 @@ use rustc_codegen_ssa::debuginfo::{
wants_c_like_enum_debuginfo,
};
use rustc_hir::def::CtorKind;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::{
bug,
mir::{GeneratorLayout, GeneratorSavedLocal},
diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
index d808f8c5f..c3f0a0033 100644
--- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs
@@ -21,12 +21,13 @@ use rustc_codegen_ssa::debuginfo::type_names;
use rustc_codegen_ssa::mir::debuginfo::{DebugScope, FunctionDebugContext, VariableKind};
use rustc_codegen_ssa::traits::*;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stable_hasher::Hash128;
use rustc_data_structures::sync::Lrc;
use rustc_hir::def_id::{DefId, DefIdMap};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir;
use rustc_middle::ty::layout::LayoutOf;
-use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
+use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, ParamEnv, Ty, TypeVisitableExt};
use rustc_session::config::{self, DebugInfo};
use rustc_session::Session;
@@ -61,7 +62,7 @@ pub struct CodegenUnitDebugContext<'ll, 'tcx> {
llcontext: &'ll llvm::Context,
llmod: &'ll llvm::Module,
builder: &'ll mut DIBuilder<'ll>,
- created_files: RefCell<FxHashMap<Option<(u128, SourceFileHash)>, &'ll DIFile>>,
+ created_files: RefCell<FxHashMap<Option<(Hash128, SourceFileHash)>, &'ll DIFile>>,
type_map: metadata::TypeMap<'ll, 'tcx>,
namespace_map: RefCell<DefIdMap<&'ll DIScope>>,
@@ -481,12 +482,12 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let names = get_parameter_names(cx, generics);
iter::zip(substs, names)
.filter_map(|(kind, name)| {
- if let GenericArgKind::Type(ty) = kind.unpack() {
+ kind.as_type().map(|ty| {
let actual_type =
cx.tcx.normalize_erasing_regions(ParamEnv::reveal_all(), ty);
let actual_type_metadata = type_di_node(cx, actual_type);
let name = name.as_str();
- Some(unsafe {
+ unsafe {
Some(llvm::LLVMRustDIBuilderCreateTemplateTypeParameter(
DIB(cx),
None,
@@ -494,10 +495,8 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
name.len(),
actual_type_metadata,
))
- })
- } else {
- None
- }
+ }
+ })
})
.collect()
} else {
@@ -530,15 +529,14 @@ impl<'ll, 'tcx> DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> {
let impl_self_ty = cx.tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
- cx.tcx.type_of(impl_def_id).skip_binder(),
+ cx.tcx.type_of(impl_def_id),
);
// Only "class" methods are generally understood by LLVM,
// so avoid methods on other types (e.g., `<*mut T>::null`).
if let ty::Adt(def, ..) = impl_self_ty.kind() && !def.is_box() {
// Again, only create type information if full debuginfo is enabled
- if cx.sess().opts.debuginfo == DebugInfo::Full
- && !impl_self_ty.needs_subst()
+ if cx.sess().opts.debuginfo == DebugInfo::Full && !impl_self_ty.has_param()
{
return (type_di_node(cx, impl_self_ty), true);
} else {
diff --git a/compiler/rustc_codegen_llvm/src/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs
index 6a575095f..164b12cf8 100644
--- a/compiler/rustc_codegen_llvm/src/declare.rs
+++ b/compiler/rustc_codegen_llvm/src/declare.rs
@@ -19,8 +19,11 @@ use crate::llvm::AttributePlace::Function;
use crate::type_::Type;
use crate::value::Value;
use rustc_codegen_ssa::traits::TypeMembershipMethods;
-use rustc_middle::ty::Ty;
-use rustc_symbol_mangling::typeid::{kcfi_typeid_for_fnabi, typeid_for_fnabi};
+use rustc_middle::ty::{Instance, Ty};
+use rustc_symbol_mangling::typeid::{
+ kcfi_typeid_for_fnabi, kcfi_typeid_for_instance, typeid_for_fnabi, typeid_for_instance,
+ TypeIdOptions,
+};
use smallvec::SmallVec;
/// Declare a function.
@@ -116,7 +119,12 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
///
/// If there’s a value with the same name already declared, the function will
/// update the declaration and return existing Value instead.
- pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value {
+ pub fn declare_fn(
+ &self,
+ name: &str,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ instance: Option<Instance<'tcx>>,
+ ) -> &'ll Value {
debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi);
// Function addresses in Rust are never significant, allowing functions to
@@ -132,13 +140,54 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> {
fn_abi.apply_attrs_llfn(self, llfn);
if self.tcx.sess.is_sanitizer_cfi_enabled() {
- let typeid = typeid_for_fnabi(self.tcx, fn_abi);
- self.set_type_metadata(llfn, typeid);
+ if let Some(instance) = instance {
+ let typeid = typeid_for_instance(self.tcx, &instance, TypeIdOptions::empty());
+ self.set_type_metadata(llfn, typeid);
+ let typeid =
+ typeid_for_instance(self.tcx, &instance, TypeIdOptions::GENERALIZE_POINTERS);
+ self.add_type_metadata(llfn, typeid);
+ let typeid =
+ typeid_for_instance(self.tcx, &instance, TypeIdOptions::NORMALIZE_INTEGERS);
+ self.add_type_metadata(llfn, typeid);
+ let typeid = typeid_for_instance(
+ self.tcx,
+ &instance,
+ TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
+ );
+ self.add_type_metadata(llfn, typeid);
+ } else {
+ let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::empty());
+ self.set_type_metadata(llfn, typeid);
+ let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::GENERALIZE_POINTERS);
+ self.add_type_metadata(llfn, typeid);
+ let typeid = typeid_for_fnabi(self.tcx, fn_abi, TypeIdOptions::NORMALIZE_INTEGERS);
+ self.add_type_metadata(llfn, typeid);
+ let typeid = typeid_for_fnabi(
+ self.tcx,
+ fn_abi,
+ TypeIdOptions::GENERALIZE_POINTERS | TypeIdOptions::NORMALIZE_INTEGERS,
+ );
+ self.add_type_metadata(llfn, typeid);
+ }
}
if self.tcx.sess.is_sanitizer_kcfi_enabled() {
- let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi);
- self.set_kcfi_type_metadata(llfn, kcfi_typeid);
+ // LLVM KCFI does not support multiple !kcfi_type attachments
+ let mut options = TypeIdOptions::empty();
+ if self.tcx.sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ options.insert(TypeIdOptions::GENERALIZE_POINTERS);
+ }
+ if self.tcx.sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ options.insert(TypeIdOptions::NORMALIZE_INTEGERS);
+ }
+
+ if let Some(instance) = instance {
+ let kcfi_typeid = kcfi_typeid_for_instance(self.tcx, &instance, options);
+ self.set_kcfi_type_metadata(llfn, kcfi_typeid);
+ } else {
+ let kcfi_typeid = kcfi_typeid_for_fnabi(self.tcx, fn_abi, options);
+ self.set_kcfi_type_metadata(llfn, kcfi_typeid);
+ }
}
llfn
diff --git a/compiler/rustc_codegen_llvm/src/errors.rs b/compiler/rustc_codegen_llvm/src/errors.rs
index bae88d942..6a9173ab4 100644
--- a/compiler/rustc_codegen_llvm/src/errors.rs
+++ b/compiler/rustc_codegen_llvm/src/errors.rs
@@ -67,7 +67,8 @@ pub(crate) struct ErrorWritingDEFFile {
#[derive(Diagnostic)]
#[diag(codegen_llvm_error_calling_dlltool)]
-pub(crate) struct ErrorCallingDllTool {
+pub(crate) struct ErrorCallingDllTool<'a> {
+ pub dlltool_path: Cow<'a, str>,
pub error: std::io::Error,
}
@@ -195,6 +196,7 @@ pub(crate) struct FromLlvmOptimizationDiag<'a> {
pub line: std::ffi::c_uint,
pub column: std::ffi::c_uint,
pub pass_name: &'a str,
+ pub kind: &'a str,
pub message: &'a str,
}
diff --git a/compiler/rustc_codegen_llvm/src/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs
index 012e25884..4e28034a8 100644
--- a/compiler/rustc_codegen_llvm/src/intrinsic.rs
+++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs
@@ -110,6 +110,7 @@ impl<'ll, 'tcx> IntrinsicCallMethods<'tcx> for Builder<'_, 'll, 'tcx> {
self.call(
simple_ty,
None,
+ None,
simple_fn,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
None,
@@ -444,7 +445,7 @@ fn try_intrinsic<'ll>(
) {
if bx.sess().panic_strategy() == PanicStrategy::Abort {
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
- bx.call(try_func_ty, None, try_func, &[data], None);
+ bx.call(try_func_ty, None, None, try_func, &[data], None);
// Return 0 unconditionally from the intrinsic call;
// we can never unwind.
let ret_align = bx.tcx().data_layout.i32_align.abi;
@@ -543,7 +544,7 @@ fn codegen_msvc_try<'ll>(
let ptr_align = bx.tcx().data_layout.pointer_align.abi;
let slot = bx.alloca(bx.type_i8p(), ptr_align);
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
- bx.invoke(try_func_ty, None, try_func, &[data], normal, catchswitch, None);
+ bx.invoke(try_func_ty, None, None, try_func, &[data], normal, catchswitch, None);
bx.switch_to_block(normal);
bx.ret(bx.const_i32(0));
@@ -587,7 +588,7 @@ fn codegen_msvc_try<'ll>(
let funclet = bx.catch_pad(cs, &[tydesc, flags, slot]);
let ptr = bx.load(bx.type_i8p(), slot, ptr_align);
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
- bx.call(catch_ty, None, catch_func, &[data, ptr], Some(&funclet));
+ bx.call(catch_ty, None, None, catch_func, &[data, ptr], Some(&funclet));
bx.catch_ret(&funclet, caught);
// The flag value of 64 indicates a "catch-all".
@@ -595,7 +596,7 @@ fn codegen_msvc_try<'ll>(
let flags = bx.const_i32(64);
let null = bx.const_null(bx.type_i8p());
let funclet = bx.catch_pad(cs, &[null, flags, null]);
- bx.call(catch_ty, None, catch_func, &[data, null], Some(&funclet));
+ bx.call(catch_ty, None, None, catch_func, &[data, null], Some(&funclet));
bx.catch_ret(&funclet, caught);
bx.switch_to_block(caught);
@@ -604,7 +605,7 @@ fn codegen_msvc_try<'ll>(
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -647,7 +648,7 @@ fn codegen_gnu_try<'ll>(
let data = llvm::get_param(bx.llfn(), 1);
let catch_func = llvm::get_param(bx.llfn(), 2);
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
- bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
+ bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
bx.switch_to_block(then);
bx.ret(bx.const_i32(0));
@@ -665,13 +666,13 @@ fn codegen_gnu_try<'ll>(
bx.add_clause(vals, tydesc);
let ptr = bx.extract_value(vals, 0);
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
- bx.call(catch_ty, None, catch_func, &[data, ptr], None);
+ bx.call(catch_ty, None, None, catch_func, &[data, ptr], None);
bx.ret(bx.const_i32(1));
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -711,7 +712,7 @@ fn codegen_emcc_try<'ll>(
let data = llvm::get_param(bx.llfn(), 1);
let catch_func = llvm::get_param(bx.llfn(), 2);
let try_func_ty = bx.type_func(&[bx.type_i8p()], bx.type_void());
- bx.invoke(try_func_ty, None, try_func, &[data], then, catch, None);
+ bx.invoke(try_func_ty, None, None, try_func, &[data], then, catch, None);
bx.switch_to_block(then);
bx.ret(bx.const_i32(0));
@@ -750,13 +751,13 @@ fn codegen_emcc_try<'ll>(
let catch_data = bx.bitcast(catch_data, bx.type_i8p());
let catch_ty = bx.type_func(&[bx.type_i8p(), bx.type_i8p()], bx.type_void());
- bx.call(catch_ty, None, catch_func, &[data, catch_data], None);
+ bx.call(catch_ty, None, None, catch_func, &[data, catch_data], None);
bx.ret(bx.const_i32(1));
});
// Note that no invoke is used here because by definition this function
// can't panic (that's what it's catching).
- let ret = bx.call(llty, None, llfn, &[try_func, data, catch_func], None);
+ let ret = bx.call(llty, None, None, llfn, &[try_func, data, catch_func], None);
let i32_align = bx.tcx().data_layout.i32_align.abi;
bx.store(ret, dest, i32_align);
}
@@ -771,7 +772,7 @@ fn gen_fn<'ll, 'tcx>(
) -> (&'ll Type, &'ll Value) {
let fn_abi = cx.fn_abi_of_fn_ptr(rust_fn_sig, ty::List::empty());
let llty = fn_abi.llvm_type(cx);
- let llfn = cx.declare_fn(name, fn_abi);
+ let llfn = cx.declare_fn(name, fn_abi, None);
cx.set_frame_pointer_type(llfn);
cx.apply_target_cpu_attr(llfn);
// FIXME(eddyb) find a nicer way to do this.
@@ -1205,6 +1206,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let c = bx.call(
fn_ty,
None,
+ None,
f,
&args.iter().map(|arg| arg.immediate()).collect::<Vec<_>>(),
None,
@@ -1423,6 +1425,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let v = bx.call(
fn_ty,
None,
+ None,
f,
&[args[1].immediate(), alignment, mask, args[0].immediate()],
None,
@@ -1564,6 +1567,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let v = bx.call(
fn_ty,
None,
+ None,
f,
&[args[0].immediate(), args[1].immediate(), alignment, mask],
None,
@@ -2037,7 +2041,7 @@ fn generic_simd_intrinsic<'ll, 'tcx>(
let fn_ty = bx.type_func(&[vec_ty, vec_ty], vec_ty);
let f = bx.declare_cfn(llvm_intrinsic, llvm::UnnamedAddr::No, fn_ty);
- let v = bx.call(fn_ty, None, f, &[lhs, rhs], None);
+ let v = bx.call(fn_ty, None, None, f, &[lhs, rhs], None);
return Ok(v);
}
diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs
index 3f77ea77e..805843e58 100644
--- a/compiler/rustc_codegen_llvm/src/lib.rs
+++ b/compiler/rustc_codegen_llvm/src/lib.rs
@@ -10,6 +10,7 @@
#![feature(iter_intersperse)]
#![feature(let_chains)]
#![feature(never_type)]
+#![feature(impl_trait_in_assoc_type)]
#![recursion_limit = "256"]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
@@ -34,10 +35,10 @@ use rustc_codegen_ssa::ModuleCodegen;
use rustc_codegen_ssa::{CodegenResults, CompiledModule};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{OptLevel, OutputFilenames, PrintRequest};
use rustc_session::Session;
@@ -69,7 +70,7 @@ mod declare;
mod errors;
mod intrinsic;
-// The following is a work around that replaces `pub mod llvm;` and that fixes issue 53912.
+// The following is a workaround that replaces `pub mod llvm;` and that fixes issue 53912.
#[path = "llvm/mod.rs"]
mod llvm_;
pub mod llvm {
diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
index 05bbdbb74..de93a64c0 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs
@@ -552,6 +552,7 @@ pub enum ArchiveKind {
K_BSD,
K_DARWIN,
K_COFF,
+ K_AIXBIG,
}
// LLVMRustThinLTOData
@@ -679,7 +680,9 @@ pub type InlineAsmDiagHandlerTy = unsafe extern "C" fn(&SMDiagnostic, *const c_v
pub mod coverageinfo {
use super::coverage_map;
- /// Aligns with [llvm::coverage::CounterMappingRegion::RegionKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L209-L230)
+ /// Corresponds to enum `llvm::coverage::CounterMappingRegion::RegionKind`.
+ ///
+ /// Must match the layout of `LLVMRustCounterMappingRegionKind`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum RegionKind {
@@ -713,7 +716,9 @@ pub mod coverageinfo {
/// array", encoded separately), and source location (start and end positions of the represented
/// code region).
///
- /// Matches LLVMRustCounterMappingRegion.
+ /// Corresponds to struct `llvm::coverage::CounterMappingRegion`.
+ ///
+ /// Must match the layout of `LLVMRustCounterMappingRegion`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct CounterMappingRegion {
@@ -2263,7 +2268,7 @@ extern "C" {
pub fn LLVMRustHasFeature(T: &TargetMachine, s: *const c_char) -> bool;
- pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine);
+ pub fn LLVMRustPrintTargetCPUs(T: &TargetMachine, cpu: *const c_char);
pub fn LLVMRustGetTargetFeaturesCount(T: &TargetMachine) -> size_t;
pub fn LLVMRustGetTargetFeature(
T: &TargetMachine,
@@ -2479,12 +2484,6 @@ extern "C" {
len: usize,
out_len: &mut usize,
) -> *const u8;
- pub fn LLVMRustThinLTOGetDICompileUnit(
- M: &Module,
- CU1: &mut *mut c_void,
- CU2: &mut *mut c_void,
- );
- pub fn LLVMRustThinLTOPatchDICompileUnit(M: &Module, CU: *mut c_void);
pub fn LLVMRustLinkerNew(M: &Module) -> &mut Linker<'_>;
pub fn LLVMRustLinkerAdd(
diff --git a/compiler/rustc_codegen_llvm/src/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
index f820e7523..4f5cc575d 100644
--- a/compiler/rustc_codegen_llvm/src/llvm/mod.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs
@@ -137,6 +137,7 @@ impl FromStr for ArchiveKind {
"bsd" => Ok(ArchiveKind::K_BSD),
"darwin" => Ok(ArchiveKind::K_DARWIN),
"coff" => Ok(ArchiveKind::K_COFF),
+ "aix_big" => Ok(ArchiveKind::K_AIXBIG),
_ => Err(()),
}
}
diff --git a/compiler/rustc_codegen_llvm/src/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs
index 46692fd5e..03be0654b 100644
--- a/compiler/rustc_codegen_llvm/src/llvm_util.rs
+++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs
@@ -16,7 +16,6 @@ use rustc_session::config::PrintRequest;
use rustc_session::Session;
use rustc_span::symbol::Symbol;
use rustc_target::spec::{MergeFunctions, PanicStrategy};
-use smallvec::{smallvec, SmallVec};
use std::ffi::{CStr, CString};
use std::path::Path;
@@ -132,6 +131,60 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
}
}
+pub enum TargetFeatureFoldStrength<'a> {
+ // The feature is only tied when enabling the feature, disabling
+ // this feature shouldn't disable the tied feature.
+ EnableOnly(&'a str),
+ // The feature is tied for both enabling and disabling this feature.
+ Both(&'a str),
+}
+
+impl<'a> TargetFeatureFoldStrength<'a> {
+ fn as_str(&self) -> &'a str {
+ match self {
+ TargetFeatureFoldStrength::EnableOnly(feat) => feat,
+ TargetFeatureFoldStrength::Both(feat) => feat,
+ }
+ }
+}
+
+pub struct LLVMFeature<'a> {
+ pub llvm_feature_name: &'a str,
+ pub dependency: Option<TargetFeatureFoldStrength<'a>>,
+}
+
+impl<'a> LLVMFeature<'a> {
+ pub fn new(llvm_feature_name: &'a str) -> Self {
+ Self { llvm_feature_name, dependency: None }
+ }
+
+ pub fn with_dependency(
+ llvm_feature_name: &'a str,
+ dependency: TargetFeatureFoldStrength<'a>,
+ ) -> Self {
+ Self { llvm_feature_name, dependency: Some(dependency) }
+ }
+
+ pub fn contains(&self, feat: &str) -> bool {
+ self.iter().any(|dep| dep == feat)
+ }
+
+ pub fn iter(&'a self) -> impl Iterator<Item = &'a str> {
+ let dependencies = self.dependency.iter().map(|feat| feat.as_str());
+ std::iter::once(self.llvm_feature_name).chain(dependencies)
+ }
+}
+
+impl<'a> IntoIterator for LLVMFeature<'a> {
+ type Item = &'a str;
+ type IntoIter = impl Iterator<Item = &'a str>;
+
+ fn into_iter(self) -> Self::IntoIter {
+ let dependencies = self.dependency.into_iter().map(|feat| feat.as_str());
+ std::iter::once(self.llvm_feature_name).chain(dependencies)
+ }
+}
+
// WARNING: the features after applying `to_llvm_features` must be known
// to LLVM or the feature detection code will walk past the end of the feature
// array, leading to crashes.
@@ -147,42 +200,65 @@ pub fn time_trace_profiler_finish(file_name: &Path) {
// Though note that Rust can also be build with an external precompiled version of LLVM
// which might lead to failures if the oldest tested / supported LLVM version
// doesn't yet support the relevant intrinsics
-pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> SmallVec<[&'a str; 2]> {
+pub fn to_llvm_features<'a>(sess: &Session, s: &'a str) -> LLVMFeature<'a> {
let arch = if sess.target.arch == "x86_64" { "x86" } else { &*sess.target.arch };
match (arch, s) {
- ("x86", "sse4.2") => smallvec!["sse4.2", "crc32"],
- ("x86", "pclmulqdq") => smallvec!["pclmul"],
- ("x86", "rdrand") => smallvec!["rdrnd"],
- ("x86", "bmi1") => smallvec!["bmi"],
- ("x86", "cmpxchg16b") => smallvec!["cx16"],
- // FIXME: These aliases are misleading, and should be removed before avx512_target_feature is
- // stabilized. They must remain until std::arch switches off them.
- // rust#100752
- ("x86", "avx512vaes") => smallvec!["vaes"],
- ("x86", "avx512gfni") => smallvec!["gfni"],
- ("x86", "avx512vpclmulqdq") => smallvec!["vpclmulqdq"],
- ("aarch64", "rcpc2") => smallvec!["rcpc-immo"],
- ("aarch64", "dpb") => smallvec!["ccpp"],
- ("aarch64", "dpb2") => smallvec!["ccdp"],
- ("aarch64", "frintts") => smallvec!["fptoint"],
- ("aarch64", "fcma") => smallvec!["complxnum"],
- ("aarch64", "pmuv3") => smallvec!["perfmon"],
- ("aarch64", "paca") => smallvec!["pauth"],
- ("aarch64", "pacg") => smallvec!["pauth"],
- // Rust ties fp and neon together. In LLVM neon implicitly enables fp,
- // but we manually enable neon when a feature only implicitly enables fp
- ("aarch64", "f32mm") => smallvec!["f32mm", "neon"],
- ("aarch64", "f64mm") => smallvec!["f64mm", "neon"],
- ("aarch64", "fhm") => smallvec!["fp16fml", "neon"],
- ("aarch64", "fp16") => smallvec!["fullfp16", "neon"],
- ("aarch64", "jsconv") => smallvec!["jsconv", "neon"],
- ("aarch64", "sve") => smallvec!["sve", "neon"],
- ("aarch64", "sve2") => smallvec!["sve2", "neon"],
- ("aarch64", "sve2-aes") => smallvec!["sve2-aes", "neon"],
- ("aarch64", "sve2-sm4") => smallvec!["sve2-sm4", "neon"],
- ("aarch64", "sve2-sha3") => smallvec!["sve2-sha3", "neon"],
- ("aarch64", "sve2-bitperm") => smallvec!["sve2-bitperm", "neon"],
- (_, s) => smallvec![s],
+ ("x86", "sse4.2") => {
+ LLVMFeature::with_dependency("sse4.2", TargetFeatureFoldStrength::EnableOnly("crc32"))
+ }
+ ("x86", "pclmulqdq") => LLVMFeature::new("pclmul"),
+ ("x86", "rdrand") => LLVMFeature::new("rdrnd"),
+ ("x86", "bmi1") => LLVMFeature::new("bmi"),
+ ("x86", "cmpxchg16b") => LLVMFeature::new("cx16"),
+ ("aarch64", "rcpc2") => LLVMFeature::new("rcpc-immo"),
+ ("aarch64", "dpb") => LLVMFeature::new("ccpp"),
+ ("aarch64", "dpb2") => LLVMFeature::new("ccdp"),
+ ("aarch64", "frintts") => LLVMFeature::new("fptoint"),
+ ("aarch64", "fcma") => LLVMFeature::new("complxnum"),
+ ("aarch64", "pmuv3") => LLVMFeature::new("perfmon"),
+ ("aarch64", "paca") => LLVMFeature::new("pauth"),
+ ("aarch64", "pacg") => LLVMFeature::new("pauth"),
+ // Rust ties fp and neon together.
+ ("aarch64", "neon") => {
+ LLVMFeature::with_dependency("neon", TargetFeatureFoldStrength::Both("fp-armv8"))
+ }
+ // In LLVM neon implicitly enables fp, but we manually enable
+ // neon when a feature only implicitly enables fp
+ ("aarch64", "f32mm") => {
+ LLVMFeature::with_dependency("f32mm", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "f64mm") => {
+ LLVMFeature::with_dependency("f64mm", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "fhm") => {
+ LLVMFeature::with_dependency("fp16fml", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "fp16") => {
+ LLVMFeature::with_dependency("fullfp16", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "jsconv") => {
+ LLVMFeature::with_dependency("jsconv", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve") => {
+ LLVMFeature::with_dependency("sve", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve2") => {
+ LLVMFeature::with_dependency("sve2", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve2-aes") => {
+ LLVMFeature::with_dependency("sve2-aes", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve2-sm4") => {
+ LLVMFeature::with_dependency("sve2-sm4", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve2-sha3") => {
+ LLVMFeature::with_dependency("sve2-sha3", TargetFeatureFoldStrength::EnableOnly("neon"))
+ }
+ ("aarch64", "sve2-bitperm") => LLVMFeature::with_dependency(
+ "sve2-bitperm",
+ TargetFeatureFoldStrength::EnableOnly("neon"),
+ ),
+ (_, s) => LLVMFeature::new(s),
}
}
@@ -280,18 +356,17 @@ fn print_target_features(sess: &Session, tm: &llvm::TargetMachine) {
let mut rustc_target_features = supported_target_features(sess)
.iter()
.map(|(feature, _gate)| {
- let desc = if let Some(llvm_feature) = to_llvm_features(sess, *feature).first() {
- // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
+ // LLVM asserts that these are sorted. LLVM and Rust both use byte comparison for these strings.
+ let llvm_feature = to_llvm_features(sess, *feature).llvm_feature_name;
+ let desc =
match llvm_target_features.binary_search_by_key(&llvm_feature, |(f, _d)| f).ok() {
Some(index) => {
known_llvm_target_features.insert(llvm_feature);
llvm_target_features[index].1
}
None => "",
- }
- } else {
- ""
- };
+ };
+
(*feature, desc)
})
.collect::<Vec<_>>();
@@ -329,7 +404,14 @@ pub(crate) fn print(req: PrintRequest, sess: &Session) {
require_inited();
let tm = create_informational_target_machine(sess);
match req {
- PrintRequest::TargetCPUs => unsafe { llvm::LLVMRustPrintTargetCPUs(tm) },
+ PrintRequest::TargetCPUs => {
+ // SAFETY generate a C compatible string from a byte slice to pass
+ // the target CPU name into LLVM, the lifetime of the reference is
+ // at least as long as the C function
+ let cpu_cstring = CString::new(handle_native(sess.target.cpu.as_ref()))
+ .unwrap_or_else(|e| bug!("failed to convert to cstring: {}", e));
+ unsafe { llvm::LLVMRustPrintTargetCPUs(tm, cpu_cstring.as_ptr()) };
+ }
PrintRequest::TargetFeatures => print_target_features(sess, tm),
_ => bug!("rustc_codegen_llvm can't handle print request: {:?}", req),
}
@@ -468,10 +550,19 @@ pub(crate) fn global_llvm_features(sess: &Session, diagnostics: bool) -> Vec<Str
// passing requests down to LLVM. This means that all in-language
// features also work on the command line instead of having two
// different names when the LLVM name and the Rust name differ.
+ let llvm_feature = to_llvm_features(sess, feature);
+
Some(
- to_llvm_features(sess, feature)
- .into_iter()
- .map(move |f| format!("{}{}", enable_disable, f)),
+ std::iter::once(format!("{}{}", enable_disable, llvm_feature.llvm_feature_name))
+ .chain(llvm_feature.dependency.into_iter().filter_map(move |feat| {
+ match (enable_disable, feat) {
+ ('-' | '+', TargetFeatureFoldStrength::Both(f))
+ | ('+', TargetFeatureFoldStrength::EnableOnly(f)) => {
+ Some(format!("{}{}", enable_disable, f))
+ }
+ _ => None,
+ }
+ })),
)
})
.flatten();
diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs
index d0ae36349..c24854b27 100644
--- a/compiler/rustc_codegen_llvm/src/mono_item.rs
+++ b/compiler/rustc_codegen_llvm/src/mono_item.rs
@@ -48,10 +48,10 @@ impl<'tcx> PreDefineMethods<'tcx> for CodegenCx<'_, 'tcx> {
visibility: Visibility,
symbol_name: &str,
) {
- assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_infer());
let fn_abi = self.fn_abi_of_instance(instance, ty::List::empty());
- let lldecl = self.declare_fn(symbol_name, fn_abi);
+ let lldecl = self.declare_fn(symbol_name, fn_abi, Some(instance));
unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
let attrs = self.tcx.codegen_fn_attrs(instance.def_id());
base::set_link_section(lldecl, attrs);
@@ -125,8 +125,7 @@ impl CodegenCx<'_, '_> {
// Thread-local variables generally don't support copy relocations.
let is_thread_local_var = llvm::LLVMIsAGlobalVariable(llval)
- .map(|v| llvm::LLVMIsThreadLocal(v) == llvm::True)
- .unwrap_or(false);
+ .is_some_and(|v| llvm::LLVMIsThreadLocal(v) == llvm::True);
if is_thread_local_var {
return false;
}
diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs
index bef4647f2..d3fad5699 100644
--- a/compiler/rustc_codegen_llvm/src/type_.rs
+++ b/compiler/rustc_codegen_llvm/src/type_.rs
@@ -291,8 +291,24 @@ impl<'ll, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
+ fn add_type_metadata(&self, function: &'ll Value, typeid: String) {
+ let typeid_metadata = self.typeid_metadata(typeid).unwrap();
+ let v = [self.const_usize(0), typeid_metadata];
+ unsafe {
+ llvm::LLVMRustGlobalAddMetadata(
+ function,
+ llvm::MD_type as c_uint,
+ llvm::LLVMValueAsMetadata(llvm::LLVMMDNodeInContext(
+ self.llcx,
+ v.as_ptr(),
+ v.len() as c_uint,
+ )),
+ )
+ }
+ }
+
fn set_type_metadata(&self, function: &'ll Value, typeid: String) {
- let typeid_metadata = self.typeid_metadata(typeid);
+ let typeid_metadata = self.typeid_metadata(typeid).unwrap();
let v = [self.const_usize(0), typeid_metadata];
unsafe {
llvm::LLVMGlobalSetMetadata(
@@ -307,13 +323,28 @@ impl<'ll, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'ll, 'tcx> {
}
}
- fn typeid_metadata(&self, typeid: String) -> &'ll Value {
- unsafe {
+ fn typeid_metadata(&self, typeid: String) -> Option<&'ll Value> {
+ Some(unsafe {
llvm::LLVMMDStringInContext(
self.llcx,
typeid.as_ptr() as *const c_char,
typeid.len() as c_uint,
)
+ })
+ }
+
+ fn add_kcfi_type_metadata(&self, function: &'ll Value, kcfi_typeid: u32) {
+ let kcfi_type_metadata = self.const_u32(kcfi_typeid);
+ unsafe {
+ llvm::LLVMRustGlobalAddMetadata(
+ function,
+ llvm::MD_kcfi_type as c_uint,
+ llvm::LLVMMDNodeInContext2(
+ self.llcx,
+ &llvm::LLVMValueAsMetadata(kcfi_type_metadata),
+ 1,
+ ),
+ )
}
}
diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml
index c55991e00..0ac12d32b 100644
--- a/compiler/rustc_codegen_ssa/Cargo.toml
+++ b/compiler/rustc_codegen_ssa/Cargo.toml
@@ -7,15 +7,14 @@ edition = "2021"
test = false
[dependencies]
-ar_archive_writer = "0.1.1"
+ar_archive_writer = "0.1.3"
bitflags = "1.2.1"
cc = "1.0.69"
itertools = "0.10.1"
tracing = "0.1"
-libc = "0.2.50"
jobserver = "0.1.22"
tempfile = "3.2"
-thorin-dwp = "0.4"
+thorin-dwp = "0.6"
pathdiff = "0.2.0"
serde_json = "1.0.59"
snap = "1"
@@ -29,6 +28,7 @@ rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
rustc_type_ir = { path = "../rustc_type_ir" }
rustc_attr = { path = "../rustc_attr" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_symbol_mangling = { path = "../rustc_symbol_mangling" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
@@ -42,7 +42,14 @@ rustc_query_system = { path = "../rustc_query_system" }
rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }
+[target.'cfg(unix)'.dependencies]
+libc = "0.2.50"
+
[dependencies.object]
-version = "0.30.1"
+version = "0.31.1"
default-features = false
features = ["read_core", "elf", "macho", "pe", "unaligned", "archive", "write"]
+
+[target.'cfg(windows)'.dependencies.windows]
+version = "0.48.0"
+features = ["Win32_Globalization"]
diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl
index 243be0e1f..9aa2b2e2b 100644
--- a/compiler/rustc_codegen_ssa/messages.ftl
+++ b/compiler/rustc_codegen_ssa/messages.ftl
@@ -1,293 +1,306 @@
-codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
-
-codegen_ssa_version_script_write_failure = failed to write version script: {$error}
+codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
-codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
+codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
-codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
+codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
-codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
+codegen_ssa_archive_build_failure =
+ failed to build archive: {$error}
-codegen_ssa_L4Bender_exporting_symbols_unimplemented = exporting symbols not implemented yet for L4Bender
+codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
-codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
+codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error}
codegen_ssa_copy_path_buf = unable to copy {$source_file} to {$output_path}: {$error}
+codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+
+codegen_ssa_erroneous_constant = erroneous constant encountered
+
+codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
+codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+
+codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error}
+codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error}
+
+codegen_ssa_failed_to_write = failed to write {$path}: {$error}
+
codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced
codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced
-codegen_ssa_create_temp_dir = couldn't create a temp dir: {$error}
+codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal`
+ .note = an unsuffixed integer value, e.g., `1`, is expected
codegen_ssa_incompatible_linking_modifiers = link modifiers combination `+bundle,+whole-archive` is unstable when generating rlibs
-codegen_ssa_add_native_library = failed to add native library {$library_path}: {$error}
-
-codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
+codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
-codegen_ssa_rlib_missing_format = could not find formats for rlibs
+codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]`
+ .note = the attribute requires exactly one argument
-codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
+codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
-codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
+codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
-codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
+codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
+codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
-codegen_ssa_extern_funcs_not_found = some `extern` functions couldn't be found; some native libraries may need to be installed or have their path specified
+codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
-codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
+codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
-codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
+codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
-codegen_ssa_thorin_read_input_failure = failed to read input file
+codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
-codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
+codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
-codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
+codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
-codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
+codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
-codegen_ssa_thorin_parse_archive_member = failed to parse archive member
+codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
-codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
+codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
-codegen_ssa_thorin_decompress_data = failed to decompress compressed section
+codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
-codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
+codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
-codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
+codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
-codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
+codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
-codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
+codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
-codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
+codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
-codegen_ssa_thorin_no_compilation_units = input object has no compilation units
+codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
-codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
+codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
-codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
+codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
-codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
+codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
-codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
+codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
-codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
+codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_parse_unit_header = failed to parse unit header
+codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_parse_unit = failed to parse unit
+codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
+codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
+codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
+codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
-codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
+codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
-codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
+codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
-codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
+codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
-codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
+codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
-codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
+codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
-codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
+codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
-codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
+codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
-codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
+codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
-codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
+codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
-codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
+codegen_ssa_invalid_no_sanitize = invalid argument for `no_sanitize`
+ .note = expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`
-codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
+codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
-codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
+codegen_ssa_ld64_unimplemented_modifier = `as-needed` modifier not implemented yet for ld64
-codegen_ssa_thorin_io = {$error}
-codegen_ssa_thorin_object_read = {$error}
-codegen_ssa_thorin_object_write = {$error}
-codegen_ssa_thorin_gimli_read = {$error}
-codegen_ssa_thorin_gimli_write = {$error}
+codegen_ssa_lib_def_write_failure = failed to write lib.def file: {$error}
codegen_ssa_link_exe_unexpected_error = `link.exe` returned an unexpected error
-codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
-
-codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
+codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
-codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
+codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
-codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
+codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
codegen_ssa_linker_not_found = linker `{$linker_path}` not found
.note = {$error}
-codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
- .note = {$error}
- .command_note = {$command_formatted}
+codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for current linker
-codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
+codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status}
-codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option.
+codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
-codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient.
+codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload
-codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
- .note = {$output}
+codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
-codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
+codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found
-codegen_ssa_stripping_debu_info_failed = stripping debug info with `{$util}` failed: {$status}
- .note = {$output}
+codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions
-codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
+codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
+ .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
-codegen_ssa_linker_file_stem = couldn't extract file stem from specified linker
+codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error}
-codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
+codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
-codegen_ssa_link_script_unavailable = can only use link script when linking with GNU-like linker
+codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
-codegen_ssa_link_script_write_failure = failed to write link script to {$path}: {$error}
+codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status}
+ .note = {$output}
-codegen_ssa_failed_to_write = failed to write {$path}: {$error}
+codegen_ssa_read_file = failed to read file: {$message}
-codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
+codegen_ssa_repair_vs_build_tools = the Visual Studio build tools may need to be repaired using the Visual Studio installer
codegen_ssa_rlib_archive_build_failure = failed to build archive from rlib: {$error}
-codegen_ssa_option_gcc_only = option `-Z gcc-ld` is used even though linker flavor is not gcc
+codegen_ssa_rlib_incompatible_dependency_formats = `{$ty1}` and `{$ty2}` do not have equivalent dependency formats (`{$list1}` vs `{$list2}`)
-codegen_ssa_extract_bundled_libs_open_file = failed to open file '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_mmap_file = failed to mmap file '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_parse_archive = failed to parse archive '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_read_entry = failed to read entry '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_archive_member = failed to get data from archive member '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_convert_name = failed to convert name '{$rlib}': {$error}
-codegen_ssa_extract_bundled_libs_write_file = failed to write file '{$rlib}': {$error}
+codegen_ssa_rlib_missing_format = could not find formats for rlibs
-codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
+codegen_ssa_rlib_not_found = could not find rlib for: `{$crate_name}`
-codegen_ssa_apple_sdk_error_sdk_path = failed to get {$sdk_name} SDK path: {$error}
+codegen_ssa_rlib_only_rmeta_found = could not find rlib for: `{$crate_name}`, found rmeta (metadata) file
-codegen_ssa_read_file = failed to read file: {$message}
+codegen_ssa_select_cpp_build_tool_workload = in the Visual Studio installer, ensure the "C++ build tools" workload is selected
-codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
+codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
-codegen_ssa_archive_build_failure =
- failed to build archive: {$error}
+codegen_ssa_specify_libraries_to_link = use the `-l` flag to specify native libraries to link
-codegen_ssa_unknown_archive_kind =
- Don't know how to build archive of type: {$kind}
+codegen_ssa_static_library_native_artifacts = Link against the following native artifacts when linking against this static library. The order and any duplication can be significant on some platforms.
-codegen_ssa_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+codegen_ssa_stripping_debug_info_failed = stripping debug info with `{$util}` failed: {$status}
+ .note = {$output}
-codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times
- .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead
+codegen_ssa_symbol_file_write_failure = failed to write symbols file: {$error}
-codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error}
+codegen_ssa_target_feature_safe_trait = `#[target_feature(..)]` cannot be applied to safe trait method
+ .label = cannot be applied to safe trait method
+ .label_def = not an `unsafe` function
-codegen_ssa_invalid_windows_subsystem = invalid windows subsystem `{$subsystem}`, only `windows` and `console` are allowed
+codegen_ssa_thorin_decompress_data = failed to decompress compressed section
-codegen_ssa_erroneous_constant = erroneous constant encountered
+codegen_ssa_thorin_duplicate_unit = duplicate split compilation unit ({$unit})
-codegen_ssa_shuffle_indices_evaluation = could not evaluate shuffle_indices at compile time
+codegen_ssa_thorin_empty_unit = unit {$unit} in input DWARF object with no data
-codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering
+codegen_ssa_thorin_gimli_read = {$error}
+codegen_ssa_thorin_gimli_write = {$error}
-codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
+codegen_ssa_thorin_incompatible_index_version = incompatible `{$section}` index version: found version {$actual}, expected version {$format}
-codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing failure memory ordering
+codegen_ssa_thorin_invalid_input_kind = input is not an archive or elf object
-codegen_ssa_unknown_atomic_operation = unknown atomic operation
+codegen_ssa_thorin_io = {$error}
+codegen_ssa_thorin_missing_dwo_name = missing path attribute to DWARF object ({$id})
-codegen_ssa_invalid_monomorphization_basic_integer_type = invalid monomorphization of `{$name}` intrinsic: expected basic integer type, found `{$ty}`
+codegen_ssa_thorin_missing_referenced_unit = unit {$unit} referenced by executable was not found
-codegen_ssa_invalid_monomorphization_basic_float_type = invalid monomorphization of `{$name}` intrinsic: expected basic float type, found `{$ty}`
+codegen_ssa_thorin_missing_required_section = input object missing required section `{$section}`
-codegen_ssa_invalid_monomorphization_float_to_int_unchecked = invalid monomorphization of `float_to_int_unchecked` intrinsic: expected basic float type, found `{$ty}`
+codegen_ssa_thorin_mixed_input_encodings = input objects haved mixed encodings
-codegen_ssa_invalid_monomorphization_floating_point_vector = invalid monomorphization of `{$name}` intrinsic: unsupported element type `{$f_ty}` of floating-point vector `{$in_ty}`
+codegen_ssa_thorin_multiple_debug_info_section = multiple `.debug_info.dwo` sections
-codegen_ssa_invalid_monomorphization_floating_point_type = invalid monomorphization of `{$name}` intrinsic: `{$in_ty}` is not a floating-point type
+codegen_ssa_thorin_multiple_debug_types_section = multiple `.debug_types.dwo` sections in a package
-codegen_ssa_invalid_monomorphization_unrecognized_intrinsic = invalid monomorphization of `{$name}` intrinsic: unrecognized intrinsic `{$name}`
+codegen_ssa_thorin_multiple_relocations = multiple relocations for section `{$section}` at offset {$offset}
-codegen_ssa_invalid_monomorphization_simd_argument = invalid monomorphization of `{$name}` intrinsic: expected SIMD argument type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_no_compilation_units = input object has no compilation units
-codegen_ssa_invalid_monomorphization_simd_input = invalid monomorphization of `{$name}` intrinsic: expected SIMD input type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_no_die = no top-level debugging information entry in compilation/type unit
-codegen_ssa_invalid_monomorphization_simd_first = invalid monomorphization of `{$name}` intrinsic: expected SIMD first type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_not_output_object_created = no output object was created from inputs
-codegen_ssa_invalid_monomorphization_simd_second = invalid monomorphization of `{$name}` intrinsic: expected SIMD second type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_not_split_unit = regular compilation unit in object (missing dwo identifier)
-codegen_ssa_invalid_monomorphization_simd_third = invalid monomorphization of `{$name}` intrinsic: expected SIMD third type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_object_read = {$error}
+codegen_ssa_thorin_object_write = {$error}
+codegen_ssa_thorin_offset_at_index = read offset at index {$index} of `.debug_str_offsets.dwo` section
-codegen_ssa_invalid_monomorphization_simd_return = invalid monomorphization of `{$name}` intrinsic: expected SIMD return type, found non-SIMD `{$ty}`
+codegen_ssa_thorin_parse_archive_member = failed to parse archive member
-codegen_ssa_invalid_monomorphization_invalid_bitmask = invalid monomorphization of `{$name}` intrinsic: invalid bitmask `{$mask_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+codegen_ssa_thorin_parse_index = failed to parse `{$section}` index section
-codegen_ssa_polymorphic_constant_too_generic = codegen encountered polymorphic constant: TooGeneric
+codegen_ssa_thorin_parse_input_archive_file = failed to parse input archive file
-codegen_ssa_invalid_monomorphization_return_length_input_type = invalid monomorphization of `{$name}` intrinsic: expected return type with length {$in_len} (same as input type `{$in_ty}`), found `{$ret_ty}` with length {$out_len}
+codegen_ssa_thorin_parse_input_file_kind = failed to parse input file kind
-codegen_ssa_invalid_monomorphization_second_argument_length = invalid monomorphization of `{$name}` intrinsic: expected second argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+codegen_ssa_thorin_parse_input_object_file = failed to parse input object file
-codegen_ssa_invalid_monomorphization_third_argument_length = invalid monomorphization of `{$name}` intrinsic: expected third argument with length {$in_len} (same as input type `{$in_ty}`), found `{$arg_ty}` with length {$out_len}
+codegen_ssa_thorin_parse_unit = failed to parse unit
-codegen_ssa_invalid_monomorphization_return_integer_type = invalid monomorphization of `{$name}` intrinsic: expected return type with integer elements, found `{$ret_ty}` with non-integer `{$out_ty}`
+codegen_ssa_thorin_parse_unit_abbreviations = failed to parse unit abbreviations
-codegen_ssa_invalid_monomorphization_simd_shuffle = invalid monomorphization of `{$name}` intrinsic: simd_shuffle index must be an array of `u32`, got `{$ty}`
+codegen_ssa_thorin_parse_unit_attribute = failed to parse unit attribute
-codegen_ssa_invalid_monomorphization_return_length = invalid monomorphization of `{$name}` intrinsic: expected return type of length {$in_len}, found `{$ret_ty}` with length {$out_len}
+codegen_ssa_thorin_parse_unit_header = failed to parse unit header
-codegen_ssa_invalid_monomorphization_return_element = invalid monomorphization of `{$name}` intrinsic: expected return element type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}` with element type `{$out_ty}`
+codegen_ssa_thorin_read_input_failure = failed to read input file
-codegen_ssa_invalid_monomorphization_shuffle_index_not_constant = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is not a constant
+codegen_ssa_thorin_relocation_with_invalid_symbol = relocation with invalid symbol for section `{$section}` at offset {$offset}
-codegen_ssa_invalid_monomorphization_shuffle_index_out_of_bounds = invalid monomorphization of `{$name}` intrinsic: shuffle index #{$arg_idx} is out of bounds (limit {$total_len})
+codegen_ssa_thorin_row_not_in_index = row {$row} found in index's hash table not present in index
-codegen_ssa_invalid_monomorphization_inserted_type = invalid monomorphization of `{$name}` intrinsic: expected inserted type `{$in_elem}` (element of input `{$in_ty}`), found `{$out_ty}`
+codegen_ssa_thorin_section_not_in_row = section not found in unit's row in index
-codegen_ssa_invalid_monomorphization_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_elem}` (element of input `{$in_ty}`), found `{$ret_ty}`
+codegen_ssa_thorin_section_without_name = section without name at offset {$offset}
-codegen_ssa_invalid_monomorphization_expected_return_type = invalid monomorphization of `{$name}` intrinsic: expected return type `{$in_ty}`, found `{$ret_ty}`
+codegen_ssa_thorin_str_at_offset = read string at offset {$offset} of `.debug_str.dwo` section
-codegen_ssa_invalid_monomorphization_mismatched_lengths = invalid monomorphization of `{$name}` intrinsic: mismatched lengths: mask length `{$m_len}` != other vector length `{$v_len}`
+codegen_ssa_thorin_top_level_die_not_unit = top-level debugging information entry is not a compilation/type unit
-codegen_ssa_invalid_monomorphization_mask_type = invalid monomorphization of `{$name}` intrinsic: mask element type is `{$ty}`, expected `i_`
+codegen_ssa_thorin_unit_not_in_index = unit {$unit} from input package is not in its index
-codegen_ssa_invalid_monomorphization_vector_argument = invalid monomorphization of `{$name}` intrinsic: vector argument `{$in_ty}`'s element type `{$in_elem}`, expected integer element type
+codegen_ssa_thorin_unsupported_relocation = unsupported relocation for section {$section} at offset {$offset}
-codegen_ssa_invalid_monomorphization_cannot_return = invalid monomorphization of `{$name}` intrinsic: cannot return `{$ret_ty}`, expected `u{$expected_int_bits}` or `[u8; {$expected_bytes}]`
+codegen_ssa_unable_to_exe_linker = could not exec the linker `{$linker_path}`
+ .note = {$error}
+ .command_note = {$command_formatted}
-codegen_ssa_invalid_monomorphization_expected_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of second argument `{$second_arg}` to be a pointer to the element type `{$in_elem}` of the first argument `{$in_ty}`, found `{$expected_element}` != `{$mutability} {$in_elem}`
+codegen_ssa_unable_to_run = unable to run `{$util}`: {$error}
-codegen_ssa_invalid_monomorphization_third_arg_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of third argument `{$third_arg}` to be a signed integer type
+codegen_ssa_unable_to_run_dsymutil = unable to run `dsymutil`: {$error}
-codegen_ssa_invalid_monomorphization_unsupported_symbol_of_size = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` of size `{$size}` to `{$ret_ty}`
+codegen_ssa_unable_to_write_debugger_visualizer = Unable to write debugger visualizer file `{$path}`: {$error}
-codegen_ssa_invalid_monomorphization_unsupported_symbol = invalid monomorphization of `{$name}` intrinsic: unsupported {$symbol} from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}`
+codegen_ssa_unknown_archive_kind =
+ Don't know how to build archive of type: {$kind}
-codegen_ssa_invalid_monomorphization_cast_fat_pointer = invalid monomorphization of `{$name}` intrinsic: cannot cast fat pointer `{$ty}`
+codegen_ssa_unknown_atomic_operation = unknown atomic operation
-codegen_ssa_invalid_monomorphization_expected_pointer = invalid monomorphization of `{$name}` intrinsic: expected pointer, got `{$ty}`
+codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic
-codegen_ssa_invalid_monomorphization_expected_usize = invalid monomorphization of `{$name}` intrinsic: expected `usize`, got `{$ty}`
+codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}`
-codegen_ssa_invalid_monomorphization_unsupported_cast = invalid monomorphization of `{$name}` intrinsic: unsupported cast from `{$in_ty}` with element `{$in_elem}` to `{$ret_ty}` with element `{$out_elem}`
+codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target
-codegen_ssa_invalid_monomorphization_unsupported_operation = invalid monomorphization of `{$name}` intrinsic: unsupported operation on `{$in_ty}` with element `{$in_elem}`
+codegen_ssa_use_cargo_directive = use the `cargo:rustc-link-lib` directive to specify the native libraries to link with Cargo (see https://doc.rust-lang.org/cargo/reference/build-scripts.html#cargorustc-link-libkindname)
-codegen_ssa_invalid_monomorphization_expected_vector_element_type = invalid monomorphization of `{$name}` intrinsic: expected element type `{$expected_element}` of vector type `{$vector_type}` to be a signed or unsigned integer type
+codegen_ssa_version_script_write_failure = failed to write version script: {$error}
+
+codegen_ssa_visual_studio_not_installed = you may need to install Visual Studio build tools with the "C++ build tools" workload
diff --git a/compiler/rustc_codegen_ssa/src/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs
index 66ec8f5f5..1c464b3ec 100644
--- a/compiler/rustc_codegen_ssa/src/back/archive.rs
+++ b/compiler/rustc_codegen_ssa/src/back/archive.rs
@@ -233,6 +233,7 @@ impl<'a> ArArchiveBuilder<'a> {
"bsd" => ArchiveKind::Bsd,
"darwin" => ArchiveKind::Darwin,
"coff" => ArchiveKind::Coff,
+ "aix_big" => ArchiveKind::AixBig,
kind => {
self.sess.emit_fatal(UnknownArchiveKind { kind });
}
diff --git a/compiler/rustc_codegen_ssa/src/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs
index eecfe13bb..8a00c42a0 100644
--- a/compiler/rustc_codegen_ssa/src/back/link.rs
+++ b/compiler/rustc_codegen_ssa/src/back/link.rs
@@ -9,6 +9,7 @@ use rustc_fs_util::fix_windows_verbatim_for_gcc;
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::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_session::config::{self, CFGuard, CrateType, DebugInfo, LdImpl, Strip};
@@ -21,7 +22,6 @@ use rustc_session::utils::NativeLibKind;
/// need out of the shared crate context before we get rid of it.
use rustc_session::{filesearch, Session};
use rustc_span::symbol::Symbol;
-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};
@@ -40,7 +40,6 @@ use regex::Regex;
use tempfile::Builder as TempFileBuilder;
use itertools::Itertools;
-use std::borrow::Borrow;
use std::cell::OnceCell;
use std::collections::BTreeSet;
use std::ffi::OsString;
@@ -54,7 +53,7 @@ use std::{env, fmt, fs, io, mem, str};
pub fn ensure_removed(diag_handler: &Handler, path: &Path) {
if let Err(e) = fs::remove_file(path) {
if e.kind() != io::ErrorKind::NotFound {
- diag_handler.err(&format!("failed to remove {}: {}", path.display(), e));
+ diag_handler.err(format!("failed to remove {}: {}", path.display(), e));
}
}
}
@@ -547,12 +546,40 @@ fn link_staticlib<'a>(
ab.build(out_filename);
- if !all_native_libs.is_empty() {
- if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
- print_native_static_libs(sess, &all_native_libs);
+ let crates = codegen_results.crate_info.used_crates.iter();
+
+ let fmts = codegen_results
+ .crate_info
+ .dependency_formats
+ .iter()
+ .find_map(|&(ty, ref list)| if ty == CrateType::Staticlib { Some(list) } else { None })
+ .expect("no dependency formats for staticlib");
+
+ let mut all_rust_dylibs = vec![];
+ for &cnum in crates {
+ match fmts.get(cnum.as_usize() - 1) {
+ Some(&Linkage::Dynamic) => {}
+ _ => continue,
+ }
+ let crate_name = codegen_results.crate_info.crate_name[&cnum];
+ let used_crate_source = &codegen_results.crate_info.used_crate_source[&cnum];
+ if let Some((path, _)) = &used_crate_source.dylib {
+ all_rust_dylibs.push(&**path);
+ } else {
+ if used_crate_source.rmeta.is_some() {
+ sess.emit_fatal(errors::LinkRlibError::OnlyRmetaFound { crate_name });
+ } else {
+ sess.emit_fatal(errors::LinkRlibError::NotFound { crate_name });
+ }
}
}
+ all_native_libs.extend_from_slice(&codegen_results.crate_info.used_libraries);
+
+ if sess.opts.prints.contains(&PrintRequest::NativeStaticLibs) {
+ print_native_static_libs(sess, &all_native_libs, &all_rust_dylibs);
+ }
+
Ok(())
}
@@ -576,17 +603,17 @@ fn link_dwarf_object<'a>(
impl<Relocations> ThorinSession<Relocations> {
fn alloc_mmap(&self, data: Mmap) -> &Mmap {
- (*self.arena_mmap.alloc(data)).borrow()
+ &*self.arena_mmap.alloc(data)
}
}
impl<Relocations> thorin::Session<Relocations> for ThorinSession<Relocations> {
fn alloc_data(&self, data: Vec<u8>) -> &[u8] {
- (*self.arena_data.alloc(data)).borrow()
+ &*self.arena_data.alloc(data)
}
fn alloc_relocation(&self, data: Relocations) -> &Relocations {
- (*self.arena_relocations.alloc(data)).borrow()
+ &*self.arena_relocations.alloc(data)
}
fn read_input(&self, path: &Path) -> std::io::Result<&[u8]> {
@@ -860,7 +887,7 @@ fn link_natively<'a>(
if !prog.status.success() {
let mut output = prog.stderr.clone();
output.extend_from_slice(&prog.stdout);
- let escaped_output = escape_string(&output);
+ let escaped_output = escape_linker_output(&output, flavor);
// FIXME: Add UI tests for this error.
let err = errors::LinkingFailed {
linker_path: &linker_path,
@@ -1052,6 +1079,83 @@ fn escape_string(s: &[u8]) -> String {
}
}
+#[cfg(not(windows))]
+fn escape_linker_output(s: &[u8], _flavour: LinkerFlavor) -> String {
+ escape_string(s)
+}
+
+/// If the output of the msvc linker is not UTF-8 and the host is Windows,
+/// then try to convert the string from the OEM encoding.
+#[cfg(windows)]
+fn escape_linker_output(s: &[u8], flavour: LinkerFlavor) -> String {
+ // This only applies to the actual MSVC linker.
+ if flavour != LinkerFlavor::Msvc(Lld::No) {
+ return escape_string(s);
+ }
+ match str::from_utf8(s) {
+ Ok(s) => return s.to_owned(),
+ Err(_) => match win::locale_byte_str_to_string(s, win::oem_code_page()) {
+ Some(s) => s,
+ // The string is not UTF-8 and isn't valid for the OEM code page
+ None => format!("Non-UTF-8 output: {}", s.escape_ascii()),
+ },
+ }
+}
+
+/// Wrappers around the Windows API.
+#[cfg(windows)]
+mod win {
+ use windows::Win32::Globalization::{
+ GetLocaleInfoEx, MultiByteToWideChar, CP_OEMCP, LOCALE_IUSEUTF8LEGACYOEMCP,
+ LOCALE_NAME_SYSTEM_DEFAULT, LOCALE_RETURN_NUMBER, MB_ERR_INVALID_CHARS,
+ };
+
+ /// Get the Windows system OEM code page. This is most notably the code page
+ /// used for link.exe's output.
+ pub fn oem_code_page() -> u32 {
+ unsafe {
+ let mut cp: u32 = 0;
+ // We're using the `LOCALE_RETURN_NUMBER` flag to return a u32.
+ // But the API requires us to pass the data as though it's a [u16] string.
+ let len = std::mem::size_of::<u32>() / std::mem::size_of::<u16>();
+ let data = std::slice::from_raw_parts_mut(&mut cp as *mut u32 as *mut u16, len);
+ let len_written = GetLocaleInfoEx(
+ LOCALE_NAME_SYSTEM_DEFAULT,
+ LOCALE_IUSEUTF8LEGACYOEMCP | LOCALE_RETURN_NUMBER,
+ Some(data),
+ );
+ if len_written as usize == len { cp } else { CP_OEMCP }
+ }
+ }
+ /// Try to convert a multi-byte string to a UTF-8 string using the given code page
+ /// The string does not need to be null terminated.
+ ///
+ /// This is implemented as a wrapper around `MultiByteToWideChar`.
+ /// See <https://learn.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-multibytetowidechar>
+ ///
+ /// It will fail if the multi-byte string is longer than `i32::MAX` or if it contains
+ /// any invalid bytes for the expected encoding.
+ pub fn locale_byte_str_to_string(s: &[u8], code_page: u32) -> Option<String> {
+ // `MultiByteToWideChar` requires a length to be a "positive integer".
+ if s.len() > isize::MAX as usize {
+ return None;
+ }
+ // Error if the string is not valid for the expected code page.
+ let flags = MB_ERR_INVALID_CHARS;
+ // Call MultiByteToWideChar twice.
+ // First to calculate the length then to convert the string.
+ let mut len = unsafe { MultiByteToWideChar(code_page, flags, s, None) };
+ if len > 0 {
+ let mut utf16 = vec![0; len as usize];
+ len = unsafe { MultiByteToWideChar(code_page, flags, s, Some(&mut utf16)) };
+ if len > 0 {
+ return utf16.get(..len as usize).map(String::from_utf16_lossy);
+ }
+ }
+ None
+ }
+}
+
fn add_sanitizer_libraries(sess: &Session, crate_type: CrateType, linker: &mut dyn Linker) {
// On macOS the runtimes are distributed as dylibs which should be linked to
// both executables and dynamic shared objects. Everywhere else the runtimes
@@ -1294,8 +1398,12 @@ enum RlibFlavor {
StaticlibBase,
}
-fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
- let lib_args: Vec<_> = all_native_libs
+fn print_native_static_libs(
+ sess: &Session,
+ all_native_libs: &[NativeLib],
+ all_rust_dylibs: &[&Path],
+) {
+ let mut lib_args: Vec<_> = all_native_libs
.iter()
.filter(|l| relevant_lib(sess, l))
.filter_map(|lib| {
@@ -1325,11 +1433,46 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) {
}
})
.collect();
+ for path in all_rust_dylibs {
+ // FIXME deduplicate with add_dynamic_crate
+
+ // Just need to tell the linker about where the library lives and
+ // what its name is
+ let parent = path.parent();
+ if let Some(dir) = parent {
+ let dir = fix_windows_verbatim_for_gcc(dir);
+ if sess.target.is_like_msvc {
+ let mut arg = String::from("/LIBPATH:");
+ arg.push_str(&dir.display().to_string());
+ lib_args.push(arg);
+ } else {
+ lib_args.push("-L".to_owned());
+ lib_args.push(dir.display().to_string());
+ }
+ }
+ let stem = path.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 };
+ let lib = &stem[prefix..];
+ let path = parent.unwrap_or_else(|| Path::new(""));
+ if sess.target.is_like_msvc {
+ // When producing a dll, the MSVC linker may not actually emit a
+ // `foo.lib` file if the dll doesn't actually export any symbols, so we
+ // check to see if the file is there and just omit linking to it if it's
+ // not present.
+ let name = format!("{}.dll.lib", lib);
+ if path.join(&name).exists() {
+ lib_args.push(name);
+ }
+ } else {
+ lib_args.push(format!("-l{}", lib));
+ }
+ }
if !lib_args.is_empty() {
sess.emit_note(errors::StaticLibraryNativeArtifacts);
// Prefix for greppability
// Note: This must not be translated as tools are allowed to depend on this exact string.
- sess.note_without_error(&format!("native-static-libs: {}", &lib_args.join(" ")));
+ sess.note_without_error(format!("native-static-libs: {}", &lib_args.join(" ")));
}
}
diff --git a/compiler/rustc_codegen_ssa/src/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs
index 65dfc325a..cd56f85cc 100644
--- a/compiler/rustc_codegen_ssa/src/back/linker.rs
+++ b/compiler/rustc_codegen_ssa/src/back/linker.rs
@@ -144,7 +144,7 @@ pub fn get_linker<'a>(
cmd,
sess,
target_cpu,
- hinted_static: false,
+ hinted_static: None,
is_ld: cc == Cc::No,
is_gnu: flavor.is_gnu(),
}) as Box<dyn Linker>,
@@ -214,7 +214,7 @@ pub struct GccLinker<'a> {
cmd: Command,
sess: &'a Session,
target_cpu: &'a str,
- hinted_static: bool, // Keeps track of the current hinting mode.
+ hinted_static: Option<bool>, // Keeps track of the current hinting mode.
// Link as ld
is_ld: bool,
is_gnu: bool,
@@ -275,9 +275,9 @@ impl<'a> GccLinker<'a> {
if !self.takes_hints() {
return;
}
- if !self.hinted_static {
+ if self.hinted_static != Some(true) {
self.linker_arg("-Bstatic");
- self.hinted_static = true;
+ self.hinted_static = Some(true);
}
}
@@ -285,9 +285,9 @@ impl<'a> GccLinker<'a> {
if !self.takes_hints() {
return;
}
- if self.hinted_static {
+ if self.hinted_static != Some(false) {
self.linker_arg("-Bdynamic");
- self.hinted_static = false;
+ self.hinted_static = Some(false);
}
}
@@ -1484,25 +1484,25 @@ impl<'a> L4Bender<'a> {
pub struct AixLinker<'a> {
cmd: Command,
sess: &'a Session,
- hinted_static: bool,
+ hinted_static: Option<bool>,
}
impl<'a> AixLinker<'a> {
pub fn new(cmd: Command, sess: &'a Session) -> AixLinker<'a> {
- AixLinker { cmd: cmd, sess: sess, hinted_static: false }
+ AixLinker { cmd: cmd, sess: sess, hinted_static: None }
}
fn hint_static(&mut self) {
- if !self.hinted_static {
+ if self.hinted_static != Some(true) {
self.cmd.arg("-bstatic");
- self.hinted_static = true;
+ self.hinted_static = Some(true);
}
}
fn hint_dynamic(&mut self) {
- if self.hinted_static {
+ if self.hinted_static != Some(false) {
self.cmd.arg("-bdynamic");
- self.hinted_static = false;
+ self.hinted_static = Some(false);
}
}
@@ -1631,7 +1631,7 @@ impl<'a> Linker for AixLinker<'a> {
}
};
if let Err(e) = res {
- self.sess.fatal(&format!("failed to write export file: {}", e));
+ self.sess.fatal(format!("failed to write export file: {}", e));
}
self.cmd.arg(format!("-bE:{}", path.to_str().unwrap()));
}
diff --git a/compiler/rustc_codegen_ssa/src/back/metadata.rs b/compiler/rustc_codegen_ssa/src/back/metadata.rs
index d5d843702..ad27b854d 100644
--- a/compiler/rustc_codegen_ssa/src/back/metadata.rs
+++ b/compiler/rustc_codegen_ssa/src/back/metadata.rs
@@ -12,9 +12,9 @@ use object::{
use snap::write::FrameEncoder;
+use object::elf::NT_GNU_PROPERTY_TYPE_0;
use rustc_data_structures::memmap::Mmap;
-use rustc_data_structures::owned_slice::try_slice_owned;
-use rustc_data_structures::sync::MetadataRef;
+use rustc_data_structures::owned_slice::{try_slice_owned, OwnedSlice};
use rustc_metadata::fs::METADATA_FILENAME;
use rustc_metadata::EncodedMetadata;
use rustc_session::cstore::MetadataLoader;
@@ -38,7 +38,7 @@ pub struct DefaultMetadataLoader;
fn load_metadata_with(
path: &Path,
f: impl for<'a> FnOnce(&'a [u8]) -> Result<&'a [u8], String>,
-) -> Result<MetadataRef, String> {
+) -> Result<OwnedSlice, String> {
let file =
File::open(path).map_err(|e| format!("failed to open file '{}': {}", path.display(), e))?;
@@ -48,7 +48,7 @@ fn load_metadata_with(
}
impl MetadataLoader for DefaultMetadataLoader {
- fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
+ fn get_rlib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
load_metadata_with(path, |data| {
let archive = object::read::archive::ArchiveFile::parse(&*data)
.map_err(|e| format!("failed to parse rlib '{}': {}", path.display(), e))?;
@@ -68,7 +68,7 @@ impl MetadataLoader for DefaultMetadataLoader {
})
}
- fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<MetadataRef, String> {
+ fn get_dylib_metadata(&self, _target: &Target, path: &Path) -> Result<OwnedSlice, String> {
load_metadata_with(path, |data| search_for_section(path, data, ".rustc"))
}
}
@@ -93,6 +93,54 @@ pub(super) fn search_for_section<'a>(
.map_err(|e| format!("failed to read {} section in '{}': {}", section, path.display(), e))
}
+fn add_gnu_property_note(
+ file: &mut write::Object<'static>,
+ architecture: Architecture,
+ binary_format: BinaryFormat,
+ endianness: Endianness,
+) {
+ // check bti protection
+ if binary_format != BinaryFormat::Elf
+ || !matches!(architecture, Architecture::X86_64 | Architecture::Aarch64)
+ {
+ return;
+ }
+
+ let section = file.add_section(
+ file.segment_name(StandardSegment::Data).to_vec(),
+ b".note.gnu.property".to_vec(),
+ SectionKind::Note,
+ );
+ let mut data: Vec<u8> = Vec::new();
+ let n_namsz: u32 = 4; // Size of the n_name field
+ let n_descsz: u32 = 16; // Size of the n_desc field
+ let n_type: u32 = NT_GNU_PROPERTY_TYPE_0; // Type of note descriptor
+ let header_values = [n_namsz, n_descsz, n_type];
+ header_values.iter().for_each(|v| {
+ data.extend_from_slice(&match endianness {
+ Endianness::Little => v.to_le_bytes(),
+ Endianness::Big => v.to_be_bytes(),
+ })
+ });
+ data.extend_from_slice(b"GNU\0"); // Owner of the program property note
+ let pr_type: u32 = match architecture {
+ Architecture::X86_64 => 0xc0000002,
+ Architecture::Aarch64 => 0xc0000000,
+ _ => unreachable!(),
+ };
+ let pr_datasz: u32 = 4; //size of the pr_data field
+ let pr_data: u32 = 3; //program property descriptor
+ let pr_padding: u32 = 0;
+ let property_values = [pr_type, pr_datasz, pr_data, pr_padding];
+ property_values.iter().for_each(|v| {
+ data.extend_from_slice(&match endianness {
+ Endianness::Little => v.to_le_bytes(),
+ Endianness::Big => v.to_be_bytes(),
+ })
+ });
+ file.append_section_data(section, &data, 8);
+}
+
pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static>> {
let endianness = match sess.target.options.endian {
Endian::Little => Endianness::Little,
@@ -140,6 +188,11 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
};
let mut file = write::Object::new(binary_format, architecture, endianness);
+ if sess.target.is_like_osx {
+ if let Some(build_version) = macho_object_build_version_for_target(&sess.target) {
+ file.set_macho_build_version(build_version)
+ }
+ }
let e_flags = match architecture {
Architecture::Mips => {
let arch = match sess.target.options.cpu.as_ref() {
@@ -205,10 +258,38 @@ pub(crate) fn create_object_file(sess: &Session) -> Option<write::Object<'static
_ => elf::ELFOSABI_NONE,
};
let abi_version = 0;
+ add_gnu_property_note(&mut file, architecture, binary_format, endianness);
file.flags = FileFlags::Elf { os_abi, abi_version, e_flags };
Some(file)
}
+/// Apple's LD, when linking for Mac Catalyst, requires object files to
+/// contain information about what they were built for (LC_BUILD_VERSION):
+/// the platform (macOS/watchOS etc), minimum OS version, and SDK version.
+/// This returns a `MachOBuildVersion` if necessary for the target.
+fn macho_object_build_version_for_target(
+ target: &Target,
+) -> Option<object::write::MachOBuildVersion> {
+ if !target.llvm_target.ends_with("-macabi") {
+ return None;
+ }
+ /// The `object` crate demands "X.Y.Z encoded in nibbles as xxxx.yy.zz"
+ /// e.g. minOS 14.0 = 0x000E0000, or SDK 16.2 = 0x00100200
+ fn pack_version((major, minor): (u32, u32)) -> u32 {
+ (major << 16) | (minor << 8)
+ }
+
+ let platform = object::macho::PLATFORM_MACCATALYST;
+ let min_os = (14, 0);
+ let sdk = (16, 2);
+
+ let mut build_version = object::write::MachOBuildVersion::default();
+ build_version.platform = platform;
+ build_version.minos = pack_version(min_os);
+ build_version.sdk = pack_version(sdk);
+ Some(build_version)
+}
+
pub enum MetadataPosition {
First,
Last,
diff --git a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
index d0fd3cd76..a8b6030ac 100644
--- a/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
+++ b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs
@@ -2,7 +2,7 @@ use crate::base::allocator_kind_for_codegen;
use std::collections::hash_map::Entry::*;
-use rustc_ast::expand::allocator::ALLOCATOR_METHODS;
+use rustc_ast::expand::allocator::{ALLOCATOR_METHODS, NO_ALLOC_SHIM_IS_UNSTABLE};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE};
@@ -11,7 +11,7 @@ use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportInfo, SymbolExportKind, SymbolExportLevel,
};
use rustc_middle::query::LocalCrate;
-use rustc_middle::ty::query::{ExternProviders, Providers};
+use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::Instance;
use rustc_middle::ty::{self, SymbolName, TyCtxt};
@@ -241,6 +241,17 @@ fn exported_symbols_provider_local(
used: false,
},
));
+
+ let exported_symbol =
+ ExportedSymbol::NoDefId(SymbolName::new(tcx, NO_ALLOC_SHIM_IS_UNSTABLE));
+ symbols.push((
+ exported_symbol,
+ SymbolExportInfo {
+ level: SymbolExportLevel::Rust,
+ kind: SymbolExportKind::Data,
+ used: false,
+ },
+ ))
}
if tcx.sess.instrument_coverage() || tcx.sess.opts.cg.profile_generate.enabled() {
@@ -333,7 +344,7 @@ fn exported_symbols_provider_local(
match *mono_item {
MonoItem::Fn(Instance { def: InstanceDef::Item(def), substs }) => {
if substs.non_erasable_generics().next().is_some() {
- let symbol = ExportedSymbol::Generic(def.did, substs);
+ let symbol = ExportedSymbol::Generic(def, substs);
symbols.push((
symbol,
SymbolExportInfo {
diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs
index 2dda4cd16..c323372bd 100644
--- a/compiler/rustc_codegen_ssa/src/back/write.rs
+++ b/compiler/rustc_codegen_ssa/src/back/write.rs
@@ -872,7 +872,7 @@ fn execute_copy_from_cache_work_item<B: ExtraBackendMethods>(
let load_from_incr_comp_dir = |output_path: PathBuf, saved_path: &str| {
let source_file = in_incr_comp_dir(&incr_comp_session_dir, saved_path);
debug!(
- "copying pre-existing module `{}` from {:?} to {}",
+ "copying preexisting module `{}` from {:?} to {}",
module.name,
source_file,
output_path.display()
@@ -1821,9 +1821,15 @@ impl SharedEmitterMain {
let source = sess
.source_map()
.new_source_file(FileName::inline_asm_source_code(&buffer), buffer);
- let source_span = Span::with_root_ctxt(source.start_pos, source.end_pos);
- let spans: Vec<_> =
- spans.iter().map(|sp| source_span.from_inner(*sp)).collect();
+ let spans: Vec<_> = spans
+ .iter()
+ .map(|sp| {
+ Span::with_root_ctxt(
+ source.normalized_byte_pos(sp.start as u32),
+ source.normalized_byte_pos(sp.end as u32),
+ )
+ })
+ .collect();
err.span_note(spans, "instantiated into assembly here");
}
@@ -1833,7 +1839,7 @@ impl SharedEmitterMain {
sess.abort_if_errors();
}
Ok(SharedEmitterMessage::Fatal(msg)) => {
- sess.fatal(&msg);
+ sess.fatal(msg);
}
Err(_) => {
break;
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs
index c5ca7936a..ab7dd1ba8 100644
--- a/compiler/rustc_codegen_ssa/src/base.rs
+++ b/compiler/rustc_codegen_ssa/src/base.rs
@@ -13,32 +13,29 @@ use crate::mir::place::PlaceRef;
use crate::traits::*;
use crate::{CachedModuleCodegen, CompiledModule, CrateInfo, MemFlags, ModuleCodegen, ModuleKind};
-use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_ast::expand::allocator::{global_fn_name, AllocatorKind, ALLOCATOR_METHODS};
use rustc_attr as attr;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::profiling::{get_resident_set_size, print_time_passes_entry};
-
-use rustc_data_structures::sync::par_iter;
-#[cfg(parallel_compiler)]
-use rustc_data_structures::sync::ParallelIterator;
+use rustc_data_structures::sync::par_map;
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_hir::lang_items::LangItem;
use rustc_metadata::EncodedMetadata;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
+use rustc_middle::middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_middle::middle::exported_symbols;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
use rustc_middle::middle::lang_items;
use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem};
+use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt};
use rustc_session::cgu_reuse_tracker::CguReuse;
use rustc_session::config::{self, CrateType, EntryFnType, OutputType};
use rustc_session::Session;
use rustc_span::symbol::sym;
use rustc_span::Symbol;
-use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
use rustc_target::abi::{Align, FIRST_VARIANT};
use std::collections::BTreeSet;
@@ -494,7 +491,7 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
(rust_main, start_ty, vec![arg_argc, arg_argv])
};
- let result = bx.call(start_ty, None, start_fn, &args, None);
+ let result = bx.call(start_ty, None, None, start_fn, &args, None);
let cast = bx.intcast(result, cx.type_int(), true);
bx.ret(cast);
@@ -689,7 +686,7 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// This likely is a temporary measure. Once we don't have to support the
// non-parallel compiler anymore, we can compile CGUs end-to-end in
// parallel and get rid of the complicated scheduling logic.
- let mut pre_compiled_cgus = if cfg!(parallel_compiler) {
+ let mut pre_compiled_cgus = if tcx.sess.threads() > 1 {
tcx.sess.time("compile_first_CGU_batch", || {
// Try to find one CGU to compile per thread.
let cgus: Vec<_> = cgu_reuse
@@ -702,12 +699,10 @@ pub fn codegen_crate<B: ExtraBackendMethods>(
// Compile the found CGUs in parallel.
let start_time = Instant::now();
- let pre_compiled_cgus = par_iter(cgus)
- .map(|(i, _)| {
- let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
- (i, module)
- })
- .collect();
+ let pre_compiled_cgus = par_map(cgus, |(i, _)| {
+ let module = backend.compile_codegen_unit(tcx, codegen_units[i].name());
+ (i, module)
+ });
total_codegen_time += start_time.elapsed();
@@ -914,7 +909,21 @@ impl CrateInfo {
missing_weak_lang_items
.iter()
.map(|item| (format!("{prefix}{item}"), SymbolExportKind::Text)),
- )
+ );
+ if tcx.allocator_kind(()).is_some() {
+ // At least one crate needs a global allocator. This crate may be placed
+ // after the crate that defines it in the linker order, in which case some
+ // linkers return an error. By adding the global allocator shim methods to
+ // the linked_symbols list, linking the generated symbols.o will ensure that
+ // circular dependencies involving the global allocator don't lead to linker
+ // errors.
+ linked_symbols.extend(ALLOCATOR_METHODS.iter().map(|method| {
+ (
+ format!("{prefix}{}", global_fn_name(method.name).as_str()),
+ SymbolExportKind::Text,
+ )
+ }));
+ }
});
}
diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
index 8542bab68..d6c230127 100644
--- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
+++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs
@@ -7,13 +7,14 @@ use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE};
use rustc_hir::{lang_items, weak_lang_items::WEAK_LANG_ITEMS, LangItem};
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::mono::Linkage;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self as ty, TyCtxt};
use rustc_session::{lint, parse::feature_err};
use rustc_span::symbol::Ident;
use rustc_span::{sym, Span};
use rustc_target::spec::{abi, SanitizerSet};
+use crate::errors;
use crate::target_features::from_target_feature;
use crate::{errors::ExpectedUsedSymbol, target_features::check_target_feature_trait_unsafe};
@@ -156,7 +157,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
None => {
// Unfortunately, unconditionally using `llvm.used` causes
// issues in handling `.init_array` with the gold linker,
- // but using `llvm.compiler.used` caused a nontrival amount
+ // but using `llvm.compiler.used` caused a nontrivial amount
// of unintentional ecosystem breakage -- particularly on
// Mach-O targets.
//
@@ -300,7 +301,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
if let Some(val) = attr.value_str() {
if val.as_str().bytes().any(|b| b == 0) {
let msg = format!("illegal null byte in link_section value: `{}`", &val);
- tcx.sess.span_err(attr.span, &msg);
+ tcx.sess.span_err(attr.span, msg);
} else {
codegen_fn_attrs.link_section = Some(val);
}
@@ -334,10 +335,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs {
codegen_fn_attrs.no_sanitize |= SanitizerSet::HWADDRESS
}
_ => {
- tcx.sess
- .struct_span_err(item.span(), "invalid argument for `no_sanitize`")
- .note("expected one of: `address`, `cfi`, `hwaddress`, `kcfi`, `memory`, `memtag`, `shadow-call-stack`, or `thread`")
- .emit();
+ tcx.sess.emit_err(errors::InvalidNoSanitize { span: item.span() });
}
}
}
@@ -594,24 +592,12 @@ fn should_inherit_track_caller(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
use rustc_ast::{LitIntType, LitKind, MetaItemLit};
- if !tcx.features().raw_dylib && tcx.sess.target.arch == "x86" {
- feature_err(
- &tcx.sess.parse_sess,
- sym::raw_dylib,
- attr.span,
- "`#[link_ordinal]` is unstable on x86",
- )
- .emit();
- }
let meta_item_list = attr.meta_item_list();
let meta_item_list = meta_item_list.as_deref();
let sole_meta_list = match meta_item_list {
Some([item]) => item.lit(),
Some(_) => {
- tcx.sess
- .struct_span_err(attr.span, "incorrect number of arguments to `#[link_ordinal]`")
- .note("the attribute requires exactly one argument")
- .emit();
+ tcx.sess.emit_err(errors::InvalidLinkOrdinalNargs { span: attr.span });
return None;
}
_ => None,
@@ -636,16 +622,13 @@ fn check_link_ordinal(tcx: TyCtxt<'_>, attr: &ast::Attribute) -> Option<u16> {
} else {
let msg = format!("ordinal value in `link_ordinal` is too large: `{}`", &ordinal);
tcx.sess
- .struct_span_err(attr.span, &msg)
+ .struct_span_err(attr.span, msg)
.note("the value may not exceed `u16::MAX`")
.emit();
None
}
} else {
- tcx.sess
- .struct_span_err(attr.span, "illegal ordinal format in `link_ordinal`")
- .note("an unsuffixed integer value, e.g., `1`, is expected")
- .emit();
+ tcx.sess.emit_err(errors::InvalidLinkOrdinalFormat { span: attr.span });
None
}
}
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
index e288760a0..1791ce4b3 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs
@@ -1,6 +1,6 @@
use rustc_middle::mir::coverage::{CounterValueReference, MappedExpressionIndex};
-/// Aligns with [llvm::coverage::Counter::CounterKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L95)
+/// Must match the layout of `LLVMRustCounterKind`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum CounterKind {
@@ -17,8 +17,10 @@ pub enum CounterKind {
/// `instrprof.increment()`)
/// * For `CounterKind::Expression`, `id` is the index into the coverage map's array of
/// counter expressions.
-/// Aligns with [llvm::coverage::Counter](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L102-L103)
-/// Important: The Rust struct layout (order and types of fields) must match its C++ counterpart.
+///
+/// Corresponds to struct `llvm::coverage::Counter`.
+///
+/// Must match the layout of `LLVMRustCounter`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct Counter {
@@ -59,7 +61,9 @@ impl Counter {
}
}
-/// Aligns with [llvm::coverage::CounterExpression::ExprKind](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L150)
+/// Corresponds to enum `llvm::coverage::CounterExpression::ExprKind`.
+///
+/// Must match the layout of `LLVMRustCounterExprKind`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub enum ExprKind {
@@ -67,9 +71,9 @@ pub enum ExprKind {
Add = 1,
}
-/// Aligns with [llvm::coverage::CounterExpression](https://github.com/rust-lang/llvm-project/blob/rustc/13.0-2021-09-30/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L152)
-/// Important: The Rust struct layout (order and types of fields) must match its C++
-/// counterpart.
+/// Corresponds to struct `llvm::coverage::CounterExpression`.
+///
+/// Must match the layout of `LLVMRustCounterExpression`.
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct CounterExpression {
diff --git a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
index 1ea130400..e4da3b8de 100644
--- a/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
+++ b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs
@@ -1,6 +1,6 @@
pub use super::ffi::*;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::coverage::{
CodeRegion, CounterValueReference, ExpressionOperandId, InjectedExpressionId,
InjectedExpressionIndex, MappedExpressionIndex, Op,
diff --git a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
index f2469fde3..6297f9134 100644
--- a/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
+++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs
@@ -12,7 +12,7 @@
// * `"` is treated as the start of a string.
use rustc_data_structures::fx::FxHashSet;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
use rustc_hir::def_id::DefId;
use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData};
use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Mutability};
@@ -94,7 +94,7 @@ fn push_debuginfo_type_name<'tcx>(
// Computing the layout can still fail here, e.g. if the target architecture
// cannot represent the type. See https://github.com/rust-lang/rust/issues/94961.
// FIXME: migrate once `rustc_middle::mir::interpret::InterpError` is translatable.
- tcx.sess.fatal(&format!("{}", e));
+ tcx.sess.fatal(format!("{}", e));
}
}
} else {
@@ -675,8 +675,7 @@ fn push_const_param<'tcx>(tcx: TyCtxt<'tcx>, ct: ty::Const<'tcx>, output: &mut S
hcx.while_hashing_spans(false, |hcx| {
ct.to_valtree().hash_stable(hcx, &mut hasher)
});
- let hash: u64 = hasher.finish();
- hash
+ hasher.finish::<Hash64>()
});
if cpp_like_debuginfo(tcx) {
diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs
index 66e7e314f..cf4893b82 100644
--- a/compiler/rustc_codegen_ssa/src/errors.rs
+++ b/compiler/rustc_codegen_ssa/src/errors.rs
@@ -424,7 +424,7 @@ pub struct UnableToRunDsymutil {
}
#[derive(Diagnostic)]
-#[diag(codegen_ssa_stripping_debu_info_failed)]
+#[diag(codegen_ssa_stripping_debug_info_failed)]
#[note]
pub struct StrippingDebugInfoFailed<'a> {
pub util: &'a str,
@@ -981,3 +981,37 @@ impl IntoDiagnosticArg for ExpectedPointerMutability {
}
}
}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_no_sanitize)]
+#[note]
+pub struct InvalidNoSanitize {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_invalid_link_ordinal_nargs)]
+#[note]
+pub struct InvalidLinkOrdinalNargs {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_illegal_link_ordinal_format)]
+#[note]
+pub struct InvalidLinkOrdinalFormat {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(codegen_ssa_target_feature_safe_trait)]
+pub struct TargetFeatureSafeTrait {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(codegen_ssa_label_def)]
+ pub def: Span,
+}
diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs
index 0ab12314b..31854c7f4 100644
--- a/compiler/rustc_codegen_ssa/src/lib.rs
+++ b/compiler/rustc_codegen_ssa/src/lib.rs
@@ -25,20 +25,22 @@ use rustc_ast as ast;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::def_id::CrateNum;
-use rustc_macros::fluent_messages;
use rustc_middle::dep_graph::WorkProduct;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Dependencies;
use rustc_middle::middle::exported_symbols::SymbolExportKind;
-use rustc_middle::ty::query::{ExternProviders, Providers};
-use rustc_serialize::opaque::{MemDecoder, MemEncoder};
+use rustc_middle::query::{ExternProviders, Providers};
+use rustc_serialize::opaque::{FileEncoder, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use rustc_session::config::{CrateType, OutputFilenames, OutputType, RUST_CGU_EXT};
use rustc_session::cstore::{self, CrateSource};
use rustc_session::utils::NativeLibKind;
+use rustc_session::Session;
use rustc_span::symbol::Symbol;
-use rustc_span::DebuggerVisualizerFile;
use std::collections::BTreeSet;
+use std::io;
use std::path::{Path, PathBuf};
pub mod back;
@@ -174,11 +176,11 @@ pub struct CodegenResults {
pub crate_info: CrateInfo,
}
-pub enum CodegenErrors<'a> {
+pub enum CodegenErrors {
WrongFileType,
EmptyVersionNumber,
EncodingVersionMismatch { version_array: String, rlink_version: u32 },
- RustcVersionMismatch { rustc_version: String, current_version: &'a str },
+ RustcVersionMismatch { rustc_version: String },
}
pub fn provide(providers: &mut Providers) {
@@ -212,21 +214,23 @@ pub fn looks_like_rust_object_file(filename: &str) -> bool {
const RLINK_VERSION: u32 = 1;
const RLINK_MAGIC: &[u8] = b"rustlink";
-const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
-
impl CodegenResults {
- pub fn serialize_rlink(codegen_results: &CodegenResults) -> Vec<u8> {
- let mut encoder = MemEncoder::new();
+ pub fn serialize_rlink(
+ sess: &Session,
+ rlink_file: &Path,
+ codegen_results: &CodegenResults,
+ ) -> Result<usize, io::Error> {
+ let mut encoder = FileEncoder::new(rlink_file)?;
encoder.emit_raw_bytes(RLINK_MAGIC);
// `emit_raw_bytes` is used to make sure that the version representation does not depend on
// Encoder's inner representation of `u32`.
encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes());
- encoder.emit_str(RUSTC_VERSION.unwrap());
+ encoder.emit_str(sess.cfg_version);
Encodable::encode(codegen_results, &mut encoder);
encoder.finish()
}
- pub fn deserialize_rlink<'a>(data: Vec<u8>) -> Result<Self, CodegenErrors<'a>> {
+ pub fn deserialize_rlink(sess: &Session, data: Vec<u8>) -> Result<Self, CodegenErrors> {
// The Decodable machinery is not used here because it panics if the input data is invalid
// and because its internal representation may change.
if !data.starts_with(RLINK_MAGIC) {
@@ -248,11 +252,9 @@ impl CodegenResults {
let mut decoder = MemDecoder::new(&data[4..], 0);
let rustc_version = decoder.read_str();
- let current_version = RUSTC_VERSION.unwrap();
- if rustc_version != current_version {
+ if rustc_version != sess.cfg_version {
return Err(CodegenErrors::RustcVersionMismatch {
rustc_version: rustc_version.to_string(),
- current_version,
});
}
diff --git a/compiler/rustc_codegen_ssa/src/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs
index 2421acab4..a8b935bd6 100644
--- a/compiler/rustc_codegen_ssa/src/meth.rs
+++ b/compiler/rustc_codegen_ssa/src/meth.rs
@@ -28,8 +28,9 @@ impl<'a, 'tcx> VirtualIndex {
if bx.cx().sess().opts.unstable_opts.virtual_function_elimination
&& bx.cx().sess().lto() == Lto::Fat
{
- let typeid =
- bx.typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)));
+ let typeid = bx
+ .typeid_metadata(typeid_for_trait_ref(bx.tcx(), expect_dyn_trait_in_self(ty)))
+ .unwrap();
let vtable_byte_offset = self.0 * bx.data_layout().pointer_size.bytes();
let func = bx.type_checked_load(llvtable, vtable_byte_offset, typeid);
bx.pointercast(func, llty)
@@ -67,10 +68,10 @@ impl<'a, 'tcx> VirtualIndex {
/// ref of the type.
fn expect_dyn_trait_in_self(ty: Ty<'_>) -> ty::PolyExistentialTraitRef<'_> {
for arg in ty.peel_refs().walk() {
- if let GenericArgKind::Type(ty) = arg.unpack() {
- if let ty::Dynamic(data, _, _) = ty.kind() {
- return data.principal().expect("expected principal trait object");
- }
+ if let GenericArgKind::Type(ty) = arg.unpack()
+ && let ty::Dynamic(data, _, _) = ty.kind()
+ {
+ return data.principal().expect("expected principal trait object");
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
index f43f1d64a..22c1f0597 100644
--- a/compiler/rustc_codegen_ssa/src/mir/analyze.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs
@@ -5,7 +5,7 @@ use super::FunctionCx;
use crate::traits::*;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::traversal;
use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{self, Location, TerminatorKind};
@@ -84,7 +84,7 @@ impl DefLocation {
struct LocalAnalyzer<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> {
fx: &'mir FunctionCx<'a, 'tcx, Bx>,
- dominators: Dominators<mir::BasicBlock>,
+ dominators: &'mir Dominators<mir::BasicBlock>,
locals: IndexVec<mir::Local, LocalKind>,
}
@@ -203,7 +203,9 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx>
self.assign(local, DefLocation::Body(location));
}
- PlaceContext::NonUse(_) | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
+ PlaceContext::NonUse(_)
+ | PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention)
+ | PlaceContext::MutatingUse(MutatingUseContext::Retag) => {}
PlaceContext::NonMutatingUse(
NonMutatingUseContext::Copy | NonMutatingUseContext::Move,
diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs
index dd8697781..3f0b64b11 100644
--- a/compiler/rustc_codegen_ssa/src/mir/block.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/block.rs
@@ -12,7 +12,6 @@ use crate::MemFlags;
use rustc_ast as ast;
use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::lang_items::LangItem;
-use rustc_index::vec::Idx;
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, ValidityRequirement};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
@@ -20,7 +19,6 @@ use rustc_middle::ty::{self, Instance, Ty};
use rustc_session::config::OptLevel;
use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol};
-use rustc_symbol_mangling::typeid::typeid_for_fnabi;
use rustc_target::abi::call::{ArgAbi, FnAbi, PassMode, Reg};
use rustc_target::abi::{self, HasDataLayout, WrappingRange};
use rustc_target::spec::abi::Abi;
@@ -164,6 +162,12 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
// do an invoke, otherwise do a call.
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
+ let fn_attrs = if bx.tcx().def_kind(fx.instance.def_id()).has_codegen_attrs() {
+ Some(bx.tcx().codegen_fn_attrs(fx.instance.def_id()))
+ } else {
+ None
+ };
+
if !fn_abi.can_unwind {
unwind = mir::UnwindAction::Unreachable;
}
@@ -191,6 +195,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
};
let invokeret = bx.invoke(
fn_ty,
+ fn_attrs,
Some(&fn_abi),
fn_ptr,
&llargs,
@@ -212,7 +217,7 @@ impl<'a, 'tcx> TerminatorCodegenHelper<'tcx> {
}
MergingSucc::False
} else {
- let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &llargs, self.funclet(fx));
+ let llret = bx.call(fn_ty, fn_attrs, Some(&fn_abi), fn_ptr, &llargs, self.funclet(fx));
if fx.mir[self.bb].is_cleanup {
// Cleanup is always the cold path. Don't inline
// drop glue. Also, when there is a deeply-nested
@@ -369,7 +374,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
if self.fn_abi.c_variadic {
// The `VaList` "spoofed" argument is just after all the real arguments.
let va_list_arg_idx = self.fn_abi.args.len();
- match self.locals[mir::Local::new(1 + va_list_arg_idx)] {
+ match self.locals[mir::Local::from_usize(1 + va_list_arg_idx)] {
LocalRef::Place(va_list) => {
bx.va_end(va_list.llval);
}
@@ -1026,7 +1031,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
});
let needs_location =
- instance.map_or(false, |i| i.def.requires_caller_location(self.cx.tcx()));
+ instance.is_some_and(|i| i.def.requires_caller_location(self.cx.tcx()));
if needs_location {
let mir_args = if let Some(num_untupled) = num_untupled {
first_args.len() + num_untupled
@@ -1052,48 +1057,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.codegen_argument(bx, location, &mut llargs, last_arg);
}
- let (is_indirect_call, fn_ptr) = match (llfn, instance) {
- (Some(llfn), _) => (true, llfn),
- (None, Some(instance)) => (false, bx.get_fn_addr(instance)),
- _ => span_bug!(span, "no llfn for call"),
+ let fn_ptr = match (instance, llfn) {
+ (Some(instance), None) => bx.get_fn_addr(instance),
+ (_, Some(llfn)) => llfn,
+ _ => span_bug!(span, "no instance or llfn for call"),
};
- // For backends that support CFI using type membership (i.e., testing whether a given
- // pointer is associated with a type identifier).
- if bx.tcx().sess.is_sanitizer_cfi_enabled() && is_indirect_call {
- // Emit type metadata and checks.
- // FIXME(rcvalle): Add support for generalized identifiers.
- // FIXME(rcvalle): Create distinct unnamed MDNodes for internal identifiers.
- let typeid = typeid_for_fnabi(bx.tcx(), fn_abi);
- let typeid_metadata = self.cx.typeid_metadata(typeid);
-
- // Test whether the function pointer is associated with the type identifier.
- let cond = bx.type_test(fn_ptr, typeid_metadata);
- let bb_pass = bx.append_sibling_block("type_test.pass");
- let bb_fail = bx.append_sibling_block("type_test.fail");
- bx.cond_br(cond, bb_pass, bb_fail);
-
- bx.switch_to_block(bb_pass);
- let merging_succ = helper.do_call(
- self,
- bx,
- fn_abi,
- fn_ptr,
- &llargs,
- target.as_ref().map(|&target| (ret_dest, target)),
- unwind,
- &copied_constant_arguments,
- false,
- );
- assert_eq!(merging_succ, MergingSucc::False);
-
- bx.switch_to_block(bb_fail);
- bx.abort();
- bx.unreachable();
-
- return MergingSucc::False;
- }
-
helper.do_call(
self,
bx,
@@ -1287,7 +1256,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
MergingSucc::False
}
- mir::TerminatorKind::Drop { place, target, unwind } => {
+ mir::TerminatorKind::Drop { place, target, unwind, replace: _ } => {
self.codegen_drop_terminator(helper, bx, place, target, unwind, mergeable_succ())
}
@@ -1481,11 +1450,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
) -> OperandRef<'tcx, Bx::Value> {
let tcx = bx.tcx();
- let mut span_to_caller_location = |mut span: Span| {
- // Remove `Inlined` marks as they pollute `expansion_cause`.
- while span.is_inlined() {
- span.remove_mark();
- }
+ let mut span_to_caller_location = |span: Span| {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = tcx.sess.source_map().lookup_char_pos(topmost.lo());
let const_loc = tcx.const_caller_location((
@@ -1631,7 +1596,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx = Bx::build(self.cx, llbb);
let llpersonality = self.cx.eh_personality();
- bx.cleanup_landing_pad(llpersonality);
+ bx.filter_landing_pad(llpersonality);
funclet = None;
}
@@ -1641,7 +1606,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (fn_abi, fn_ptr) = common::build_langcall(&bx, None, LangItem::PanicCannotUnwind);
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
- let llret = bx.call(fn_ty, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
+ let llret = bx.call(fn_ty, None, Some(&fn_abi), fn_ptr, &[], funclet.as_ref());
bx.do_not_inline(llret);
bx.unreachable();
diff --git a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
index d049bafb8..bba2800fb 100644
--- a/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs
@@ -1,5 +1,5 @@
use crate::traits::*;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir;
use rustc_middle::ty;
@@ -8,7 +8,7 @@ use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_session::config::DebugInfo;
use rustc_span::symbol::{kw, Symbol};
use rustc_span::{BytePos, Span};
-use rustc_target::abi::{Abi, FieldIdx, Size, VariantIdx};
+use rustc_target::abi::{Abi, FieldIdx, FieldsShape, Size, VariantIdx};
use super::operand::{OperandRef, OperandValue};
use super::place::PlaceRef;
@@ -41,6 +41,9 @@ pub struct PerLocalVarDebugInfo<'tcx, D> {
/// `.place.projection` from `mir::VarDebugInfo`.
pub projection: &'tcx ty::List<mir::PlaceElem<'tcx>>,
+
+ /// `references` from `mir::VarDebugInfo`.
+ pub references: u8,
}
#[derive(Clone, Copy, Debug)]
@@ -80,6 +83,7 @@ trait DebugInfoOffsetLocation<'tcx, Bx> {
fn deref(&self, bx: &mut Bx) -> Self;
fn layout(&self) -> TyAndLayout<'tcx>;
fn project_field(&self, bx: &mut Bx, field: FieldIdx) -> Self;
+ fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self;
fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self;
}
@@ -98,6 +102,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
PlaceRef::project_field(*self, bx, field.index())
}
+ fn project_constant_index(&self, bx: &mut Bx, offset: u64) -> Self {
+ let lloffset = bx.cx().const_usize(offset);
+ self.project_index(bx, lloffset)
+ }
+
fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
self.project_downcast(bx, variant)
}
@@ -120,6 +129,10 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> DebugInfoOffsetLocation<'tcx, Bx>
self.field(bx.cx(), field.index())
}
+ fn project_constant_index(&self, bx: &mut Bx, index: u64) -> Self {
+ self.field(bx.cx(), index as usize)
+ }
+
fn downcast(&self, bx: &mut Bx, variant: VariantIdx) -> Self {
self.for_variant(bx.cx(), variant)
}
@@ -165,6 +178,18 @@ fn calculate_debuginfo_offset<
mir::ProjectionElem::Downcast(_, variant) => {
place = place.downcast(bx, variant);
}
+ mir::ProjectionElem::ConstantIndex {
+ offset: index,
+ min_length: _,
+ from_end: false,
+ } => {
+ let offset = indirect_offsets.last_mut().unwrap_or(&mut direct_offset);
+ let FieldsShape::Array { stride, count: _ } = place.layout().fields else {
+ span_bug!(var.source_info.span, "ConstantIndex on non-array type {:?}", place.layout())
+ };
+ *offset += stride * index;
+ place = place.project_constant_index(bx, index);
+ }
_ => {
// Sanity check for `can_use_in_debuginfo`.
debug_assert!(!elem.can_use_in_debuginfo());
@@ -293,6 +318,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
dbg_var,
fragment: None,
projection: ty::List::empty(),
+ references: 0,
})
}
} else {
@@ -358,55 +384,74 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let vars = vars.iter().cloned().chain(fallback_var);
for var in vars {
- let Some(dbg_var) = var.dbg_var else { continue };
- let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
-
- let DebugInfoOffset { direct_offset, indirect_offsets, result: _ } =
- calculate_debuginfo_offset(bx, local, &var, base.layout);
-
- // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
- // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
- // not DWARF and LLVM doesn't support translating the resulting
- // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
- // Creating extra allocas on the stack makes the resulting debug info simple enough
- // that LLVM can generate correct CodeView records and thus the values appear in the
- // debugger. (#83709)
- let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
- && self.mir.local_kind(local) == mir::LocalKind::Arg
- // LLVM can handle simple things but anything more complex than just a direct
- // offset or one indirect offset of 0 is too complex for it to generate CV records
- // correctly.
- && (direct_offset != Size::ZERO
- || !matches!(&indirect_offsets[..], [Size::ZERO] | []));
-
- if should_create_individual_allocas {
- let DebugInfoOffset { direct_offset: _, indirect_offsets: _, result: place } =
- calculate_debuginfo_offset(bx, local, &var, base);
-
- // Create a variable which will be a pointer to the actual value
- let ptr_ty = bx
- .tcx()
- .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty });
- let ptr_layout = bx.layout_of(ptr_ty);
- let alloca = PlaceRef::alloca(bx, ptr_layout);
- bx.set_var_name(alloca.llval, &(var.name.to_string() + ".dbg.spill"));
-
- // Write the pointer to the variable
- bx.store(place.llval, alloca.llval, alloca.align);
-
- // Point the debug info to `*alloca` for the current variable
- bx.dbg_var_addr(dbg_var, dbg_loc, alloca.llval, Size::ZERO, &[Size::ZERO], None);
- } else {
- bx.dbg_var_addr(
- dbg_var,
- dbg_loc,
- base.llval,
- direct_offset,
- &indirect_offsets,
- None,
- );
+ self.debug_introduce_local_as_var(bx, local, base, var);
+ }
+ }
+
+ fn debug_introduce_local_as_var(
+ &self,
+ bx: &mut Bx,
+ local: mir::Local,
+ mut base: PlaceRef<'tcx, Bx::Value>,
+ var: PerLocalVarDebugInfo<'tcx, Bx::DIVariable>,
+ ) {
+ let Some(dbg_var) = var.dbg_var else { return };
+ let Some(dbg_loc) = self.dbg_loc(var.source_info) else { return };
+
+ let DebugInfoOffset { mut direct_offset, indirect_offsets, result: _ } =
+ calculate_debuginfo_offset(bx, local, &var, base.layout);
+ let mut indirect_offsets = &indirect_offsets[..];
+
+ // When targeting MSVC, create extra allocas for arguments instead of pointing multiple
+ // dbg_var_addr() calls into the same alloca with offsets. MSVC uses CodeView records
+ // not DWARF and LLVM doesn't support translating the resulting
+ // [DW_OP_deref, DW_OP_plus_uconst, offset, DW_OP_deref] debug info to CodeView.
+ // Creating extra allocas on the stack makes the resulting debug info simple enough
+ // that LLVM can generate correct CodeView records and thus the values appear in the
+ // debugger. (#83709)
+ let should_create_individual_allocas = bx.cx().sess().target.is_like_msvc
+ && self.mir.local_kind(local) == mir::LocalKind::Arg
+ // LLVM can handle simple things but anything more complex than just a direct
+ // offset or one indirect offset of 0 is too complex for it to generate CV records
+ // correctly.
+ && (direct_offset != Size::ZERO || !matches!(indirect_offsets, [Size::ZERO] | []));
+
+ let create_alloca = |bx: &mut Bx, place: PlaceRef<'tcx, Bx::Value>, refcount| {
+ // Create a variable which will be a pointer to the actual value
+ let ptr_ty = bx
+ .tcx()
+ .mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: place.layout.ty });
+ let ptr_layout = bx.layout_of(ptr_ty);
+ let alloca = PlaceRef::alloca(bx, ptr_layout);
+ bx.set_var_name(alloca.llval, &format!("{}.ref{}.dbg.spill", var.name, refcount));
+
+ // Write the pointer to the variable
+ bx.store(place.llval, alloca.llval, alloca.align);
+
+ // Point the debug info to `*alloca` for the current variable
+ alloca
+ };
+
+ if var.references > 0 {
+ base = calculate_debuginfo_offset(bx, local, &var, base).result;
+
+ // Point the debug info to `&...&base == alloca` for the current variable
+ for refcount in 0..var.references {
+ base = create_alloca(bx, base, refcount);
}
+
+ direct_offset = Size::ZERO;
+ indirect_offsets = &[];
+ } else if should_create_individual_allocas {
+ let place = calculate_debuginfo_offset(bx, local, &var, base).result;
+
+ // Point the debug info to `*alloca` for the current variable
+ base = create_alloca(bx, place, 0);
+ direct_offset = Size::ZERO;
+ indirect_offsets = &[Size::ZERO];
}
+
+ bx.dbg_var_addr(dbg_var, dbg_loc, base.llval, direct_offset, indirect_offsets, None);
}
pub fn debug_introduce_locals(&self, bx: &mut Bx) {
@@ -439,7 +484,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
};
let dbg_var = dbg_scope_and_span.map(|(dbg_scope, _, span)| {
- let (var_ty, var_kind) = match var.value {
+ let (mut var_ty, var_kind) = match var.value {
mir::VarDebugInfoContents::Place(place) => {
let var_ty = self.monomorphized_place_ty(place.as_ref());
let var_kind = if let Some(arg_index) = var.argument_index
@@ -476,6 +521,11 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
};
+ for _ in 0..var.references {
+ var_ty =
+ bx.tcx().mk_ptr(ty::TypeAndMut { mutbl: mir::Mutability::Mut, ty: var_ty });
+ }
+
self.cx.create_dbg_var(var.name, var_ty, dbg_scope, var_kind, span)
});
@@ -487,6 +537,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
dbg_var,
fragment: None,
projection: place.projection,
+ references: var.references,
});
}
mir::VarDebugInfoContents::Const(c) => {
@@ -494,6 +545,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let Some(dbg_loc) = self.dbg_loc(var.source_info) else { continue };
if let Ok(operand) = self.eval_mir_constant_to_operand(bx, &c) {
+ self.set_debug_loc(bx, var.source_info);
let base = Self::spill_operand_to_stack(
&operand,
Some(var.name.to_string()),
@@ -539,6 +591,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
Some(fragment_start..fragment_start + fragment_layout.size)
},
projection: place.projection,
+ references: var.references,
});
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
index 7af7fc92d..1479242f2 100644
--- a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs
@@ -135,13 +135,6 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
.unwrap();
OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx)
}
- sym::offset => {
- let ty = substs.type_at(0);
- let layout = bx.layout_of(ty);
- let ptr = args[0].immediate();
- let offset = args[1].immediate();
- bx.inbounds_gep(bx.backend_type(layout), ptr, &[offset])
- }
sym::arith_offset => {
let ty = substs.type_at(0);
let layout = bx.layout_of(ty);
diff --git a/compiler/rustc_codegen_ssa/src/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs
index 3dadb33c9..1204c99e5 100644
--- a/compiler/rustc_codegen_ssa/src/mir/mod.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs
@@ -9,7 +9,7 @@ use rustc_target::abi::call::{FnAbi, PassMode};
use std::iter;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use self::debuginfo::{FunctionDebugContext, PerLocalVarDebugInfo};
use self::place::PlaceRef;
@@ -111,7 +111,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
self.instance.subst_mir_and_normalize_erasing_regions(
self.cx.tcx(),
ty::ParamEnv::reveal_all(),
- value,
+ ty::EarlyBinder(value),
)
}
}
@@ -152,7 +152,7 @@ pub fn codegen_mir<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
cx: &'a Bx::CodegenCx,
instance: Instance<'tcx>,
) {
- assert!(!instance.substs.needs_infer());
+ assert!(!instance.substs.has_infer());
let llfn = cx.get_fn(instance);
@@ -304,7 +304,17 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
bug!("spread argument isn't a tuple?!");
};
- let place = PlaceRef::alloca(bx, bx.layout_of(arg_ty));
+ let layout = bx.layout_of(arg_ty);
+
+ // FIXME: support unsized params in "rust-call" ABI
+ if layout.is_unsized() {
+ span_bug!(
+ arg_decl.source_info.span,
+ "\"rust-call\" ABI does not support unsized params",
+ );
+ }
+
+ let place = PlaceRef::alloca(bx, layout);
for i in 0..tupled_arg_tys.len() {
let arg = &fx.fn_abi.args[idx];
idx += 1;
diff --git a/compiler/rustc_codegen_ssa/src/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs
index b37797fef..2301c3ef1 100644
--- a/compiler/rustc_codegen_ssa/src/mir/operand.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs
@@ -2,6 +2,7 @@ use super::place::PlaceRef;
use super::{FunctionCx, LocalRef};
use crate::base;
+use crate::common::TypeKind;
use crate::glue;
use crate::traits::*;
use crate::MemFlags;
@@ -236,19 +237,47 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> {
};
match (&mut val, field.abi) {
- (OperandValue::Immediate(llval), _) => {
+ (
+ OperandValue::Immediate(llval),
+ Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. },
+ ) => {
// Bools in union fields needs to be truncated.
*llval = bx.to_immediate(*llval, field);
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- *llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field));
+ let ty = bx.cx().immediate_backend_type(field);
+ if bx.type_kind(ty) == TypeKind::Pointer {
+ *llval = bx.pointercast(*llval, ty);
+ }
}
(OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => {
// Bools in union fields needs to be truncated.
*a = bx.to_immediate_scalar(*a, a_abi);
*b = bx.to_immediate_scalar(*b, b_abi);
// HACK(eddyb) have to bitcast pointers until LLVM removes pointee types.
- *a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true));
- *b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true));
+ let a_ty = bx.cx().scalar_pair_element_backend_type(field, 0, true);
+ let b_ty = bx.cx().scalar_pair_element_backend_type(field, 1, true);
+ if bx.type_kind(a_ty) == TypeKind::Pointer {
+ *a = bx.pointercast(*a, a_ty);
+ }
+ if bx.type_kind(b_ty) == TypeKind::Pointer {
+ *b = bx.pointercast(*b, b_ty);
+ }
+ }
+ // Newtype vector of array, e.g. #[repr(simd)] struct S([i32; 4]);
+ (OperandValue::Immediate(llval), Abi::Aggregate { sized: true }) => {
+ assert!(matches!(self.layout.abi, Abi::Vector { .. }));
+
+ let llty = bx.cx().backend_type(self.layout);
+ let llfield_ty = bx.cx().backend_type(field);
+
+ // Can't bitcast an aggregate, so round trip through memory.
+ let lltemp = bx.alloca(llfield_ty, field.align.abi);
+ let llptr = bx.pointercast(lltemp, bx.cx().type_ptr_to(llty));
+ bx.store(*llval, llptr, field.align.abi);
+ *llval = bx.load(llfield_ty, lltemp, field.align.abi);
+ }
+ (OperandValue::Immediate(_), Abi::Uninhabited | Abi::Aggregate { sized: false }) => {
+ bug!()
}
(OperandValue::Pair(..), _) => bug!(),
(OperandValue::Ref(..), _) => bug!(),
@@ -373,8 +402,6 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
indirect_dest: PlaceRef<'tcx, V>,
) {
debug!("OperandRef::store_unsized: operand={:?}, indirect_dest={:?}", self, indirect_dest);
- let flags = MemFlags::empty();
-
// `indirect_dest` must have `*mut T` type. We extract `T` out of it.
let unsized_ty = indirect_dest
.layout
@@ -387,17 +414,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue<V> {
bug!("store_unsized called with a sized value")
};
- // FIXME: choose an appropriate alignment, or use dynamic align somehow
- let max_align = Align::from_bits(128).unwrap();
- let min_align = Align::from_bits(8).unwrap();
-
- // Allocate an appropriate region on the stack, and copy the value into it
- let (llsize, _) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
- let lldst = bx.byte_array_alloca(llsize, max_align);
- bx.memcpy(lldst, max_align, llptr, min_align, llsize, flags);
+ // Allocate an appropriate region on the stack, and copy the value into it. Since alloca
+ // doesn't support dynamic alignment, we allocate an extra align - 1 bytes, and align the
+ // pointer manually.
+ let (size, align) = glue::size_and_align_of_dst(bx, unsized_ty, Some(llextra));
+ let one = bx.const_usize(1);
+ let align_minus_1 = bx.sub(align, one);
+ let size_extra = bx.add(size, align_minus_1);
+ let min_align = Align::ONE;
+ let alloca = bx.byte_array_alloca(size_extra, min_align);
+ let address = bx.ptrtoint(alloca, bx.type_isize());
+ let neg_address = bx.neg(address);
+ let offset = bx.and(neg_address, align_minus_1);
+ let dst = bx.inbounds_gep(bx.type_i8(), alloca, &[offset]);
+ bx.memcpy(dst, min_align, llptr, min_align, size, MemFlags::empty());
// Store the allocated region and the extra to the indirect place.
- let indirect_operand = OperandValue::Pair(lldst, llextra);
+ let indirect_operand = OperandValue::Pair(dst, llextra);
indirect_operand.store(bx, indirect_dest);
}
}
diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
index d88226f5d..6e7065713 100644
--- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
+++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs
@@ -12,6 +12,7 @@ use rustc_middle::mir::Operand;
use rustc_middle::ty::cast::{CastTy, IntTy};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout};
use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt};
+use rustc_session::config::OptLevel;
use rustc_span::source_map::{Span, DUMMY_SP};
use rustc_target::abi::{self, FIRST_VARIANT};
@@ -231,10 +232,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
(ScalarOrZst::Scalar(in_scalar), ScalarOrZst::Scalar(out_scalar))
if in_scalar.size(self.cx) == out_scalar.size(self.cx) =>
{
+ let operand_bty = bx.backend_type(operand.layout);
let cast_bty = bx.backend_type(cast);
- Some(OperandValue::Immediate(
- self.transmute_immediate(bx, imm, in_scalar, out_scalar, cast_bty),
- ))
+ Some(OperandValue::Immediate(self.transmute_immediate(
+ bx,
+ imm,
+ in_scalar,
+ operand_bty,
+ out_scalar,
+ cast_bty,
+ )))
}
_ => None,
}
@@ -250,11 +257,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
&& in_a.size(self.cx) == out_a.size(self.cx)
&& in_b.size(self.cx) == out_b.size(self.cx)
{
+ let in_a_ibty = bx.scalar_pair_element_backend_type(operand.layout, 0, false);
+ let in_b_ibty = bx.scalar_pair_element_backend_type(operand.layout, 1, false);
let out_a_ibty = bx.scalar_pair_element_backend_type(cast, 0, false);
let out_b_ibty = bx.scalar_pair_element_backend_type(cast, 1, false);
Some(OperandValue::Pair(
- self.transmute_immediate(bx, imm_a, in_a, out_a, out_a_ibty),
- self.transmute_immediate(bx, imm_b, in_b, out_b, out_b_ibty),
+ self.transmute_immediate(bx, imm_a, in_a, in_a_ibty, out_a, out_a_ibty),
+ self.transmute_immediate(bx, imm_b, in_b, in_b_ibty, out_b, out_b_ibty),
))
} else {
None
@@ -273,6 +282,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx: &mut Bx,
mut imm: Bx::Value,
from_scalar: abi::Scalar,
+ from_backend_ty: Bx::Type,
to_scalar: abi::Scalar,
to_backend_ty: Bx::Type,
) -> Bx::Value {
@@ -280,6 +290,13 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
use abi::Primitive::*;
imm = bx.from_immediate(imm);
+
+ // When scalars are passed by value, there's no metadata recording their
+ // valid ranges. For example, `char`s are passed as just `i32`, with no
+ // way for LLVM to know that they're 0x10FFFF at most. Thus we assume
+ // the range of the input value too, not just the output range.
+ self.assume_scalar_range(bx, imm, from_scalar, from_backend_ty);
+
imm = match (from_scalar.primitive(), to_scalar.primitive()) {
(Int(..) | F32 | F64, Int(..) | F32 | F64) => bx.bitcast(imm, to_backend_ty),
(Pointer(..), Pointer(..)) => bx.pointercast(imm, to_backend_ty),
@@ -294,10 +311,55 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.bitcast(int_imm, to_backend_ty)
}
};
+ self.assume_scalar_range(bx, imm, to_scalar, to_backend_ty);
imm = bx.to_immediate_scalar(imm, to_scalar);
imm
}
+ fn assume_scalar_range(
+ &self,
+ bx: &mut Bx,
+ imm: Bx::Value,
+ scalar: abi::Scalar,
+ backend_ty: Bx::Type,
+ ) {
+ if matches!(self.cx.sess().opts.optimize, OptLevel::No | OptLevel::Less)
+ // For now, the critical niches are all over `Int`eger values.
+ // Should floating-point values or pointers ever get more complex
+ // niches, then this code will probably want to handle them too.
+ || !matches!(scalar.primitive(), abi::Primitive::Int(..))
+ || scalar.is_always_valid(self.cx)
+ {
+ return;
+ }
+
+ let abi::WrappingRange { start, end } = scalar.valid_range(self.cx);
+
+ if start <= end {
+ if start > 0 {
+ let low = bx.const_uint_big(backend_ty, start);
+ let cmp = bx.icmp(IntPredicate::IntUGE, imm, low);
+ bx.assume(cmp);
+ }
+
+ let type_max = scalar.size(self.cx).unsigned_int_max();
+ if end < type_max {
+ let high = bx.const_uint_big(backend_ty, end);
+ let cmp = bx.icmp(IntPredicate::IntULE, imm, high);
+ bx.assume(cmp);
+ }
+ } else {
+ let low = bx.const_uint_big(backend_ty, start);
+ let cmp_low = bx.icmp(IntPredicate::IntUGE, imm, low);
+
+ let high = bx.const_uint_big(backend_ty, end);
+ let cmp_high = bx.icmp(IntPredicate::IntULE, imm, high);
+
+ let or = bx.or(cmp_low, cmp_high);
+ bx.assume(or);
+ }
+ }
+
pub fn codegen_rvalue_unsized(
&mut self,
bx: &mut Bx,
@@ -604,13 +666,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
}
}
- mir::Rvalue::NullaryOp(null_op, ty) => {
+ mir::Rvalue::NullaryOp(ref null_op, ty) => {
let ty = self.monomorphize(ty);
assert!(bx.cx().type_is_sized(ty));
let layout = bx.cx().layout_of(ty);
let val = match null_op {
mir::NullOp::SizeOf => layout.size.bytes(),
mir::NullOp::AlignOf => layout.align.abi.bytes(),
+ mir::NullOp::OffsetOf(fields) => {
+ layout.offset_of_subfield(bx.cx(), fields.iter().map(|f| f.index())).bytes()
+ }
};
let val = bx.cx().const_usize(val);
let tcx = self.cx.tcx();
@@ -632,7 +697,12 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let fn_ptr = bx.get_fn_addr(instance);
let fn_abi = bx.fn_abi_of_instance(instance, ty::List::empty());
let fn_ty = bx.fn_decl_backend_type(&fn_abi);
- bx.call(fn_ty, Some(fn_abi), fn_ptr, &[], None)
+ let fn_attrs = if bx.tcx().def_kind(instance.def_id()).has_codegen_attrs() {
+ Some(bx.tcx().codegen_fn_attrs(instance.def_id()))
+ } else {
+ None
+ };
+ bx.call(fn_ty, fn_attrs, Some(fn_abi), fn_ptr, &[], None)
} else {
bx.get_static(def_id)
};
@@ -754,8 +824,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
.builtin_deref(true)
.unwrap_or_else(|| bug!("deref of non-pointer {:?}", input_ty))
.ty;
- let llty = bx.cx().backend_type(bx.cx().layout_of(pointee_type));
- bx.inbounds_gep(llty, lhs, &[rhs])
+ let pointee_layout = bx.cx().layout_of(pointee_type);
+ if pointee_layout.is_zst() {
+ // `Offset` works in terms of the size of pointee,
+ // so offsetting a pointer to ZST is a noop.
+ lhs
+ } else {
+ let llty = bx.cx().backend_type(pointee_layout);
+ bx.inbounds_gep(llty, lhs, &[rhs])
+ }
}
mir::BinOp::Shl => common::build_unchecked_lshift(bx, lhs, rhs),
mir::BinOp::Shr => common::build_unchecked_rshift(bx, input_ty, lhs, rhs),
diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs
index 611dd3d1c..c5976a654 100644
--- a/compiler/rustc_codegen_ssa/src/target_features.rs
+++ b/compiler/rustc_codegen_ssa/src/target_features.rs
@@ -1,3 +1,4 @@
+use crate::errors;
use rustc_ast::ast;
use rustc_attr::InstructionSetAttr;
use rustc_data_structures::fx::FxHashMap;
@@ -7,7 +8,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_session::Session;
@@ -172,16 +173,13 @@ const X86_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("avx512dq", Some(sym::avx512_target_feature)),
("avx512er", Some(sym::avx512_target_feature)),
("avx512f", Some(sym::avx512_target_feature)),
- ("avx512gfni", Some(sym::avx512_target_feature)),
("avx512ifma", Some(sym::avx512_target_feature)),
("avx512pf", Some(sym::avx512_target_feature)),
- ("avx512vaes", Some(sym::avx512_target_feature)),
("avx512vbmi", Some(sym::avx512_target_feature)),
("avx512vbmi2", Some(sym::avx512_target_feature)),
("avx512vl", Some(sym::avx512_target_feature)),
("avx512vnni", Some(sym::avx512_target_feature)),
("avx512vp2intersect", Some(sym::avx512_target_feature)),
- ("avx512vpclmulqdq", Some(sym::avx512_target_feature)),
("avx512vpopcntdq", Some(sym::avx512_target_feature)),
("bmi1", None),
("bmi2", None),
@@ -252,6 +250,7 @@ const RISCV_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
("f", Some(sym::riscv_target_feature)),
("m", Some(sym::riscv_target_feature)),
("relax", Some(sym::riscv_target_feature)),
+ ("unaligned-scalar-mem", Some(sym::riscv_target_feature)),
("v", Some(sym::riscv_target_feature)),
("zba", Some(sym::riscv_target_feature)),
("zbb", Some(sym::riscv_target_feature)),
@@ -369,7 +368,7 @@ pub fn from_target_feature(
let Some(feature_gate) = supported_target_features.get(feature) else {
let msg =
format!("the feature named `{}` is not valid for this target", feature);
- let mut err = tcx.sess.struct_span_err(item.span(), &msg);
+ let mut err = tcx.sess.struct_span_err(item.span(), msg);
err.span_label(
item.span(),
format!("`{}` is not valid for this target", feature),
@@ -407,7 +406,7 @@ pub fn from_target_feature(
&tcx.sess.parse_sess,
feature_gate.unwrap(),
item.span(),
- &format!("the target feature `{}` is currently unstable", feature),
+ format!("the target feature `{}` is currently unstable", feature),
)
.emit();
}
@@ -443,14 +442,10 @@ pub fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_s
if let DefKind::AssocFn = tcx.def_kind(id) {
let parent_id = tcx.local_parent(id);
if let DefKind::Trait | DefKind::Impl { of_trait: true } = tcx.def_kind(parent_id) {
- tcx.sess
- .struct_span_err(
- attr_span,
- "`#[target_feature(..)]` cannot be applied to safe trait method",
- )
- .span_label(attr_span, "cannot be applied to safe trait method")
- .span_label(tcx.def_span(id), "not an `unsafe` function")
- .emit();
+ tcx.sess.emit_err(errors::TargetFeatureSafeTrait {
+ span: attr_span,
+ def: tcx.def_span(id),
+ });
}
}
}
diff --git a/compiler/rustc_codegen_ssa/src/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs
index 64bebe50d..d83bfc740 100644
--- a/compiler/rustc_codegen_ssa/src/traits/backend.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs
@@ -1,3 +1,5 @@
+use std::any::Any;
+
use super::write::WriteBackendMethods;
use super::CodegenObject;
use crate::back::write::TargetMachineFactoryFn;
@@ -5,11 +7,12 @@ use crate::{CodegenResults, ModuleCodegen};
use rustc_ast::expand::allocator::AllocatorKind;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::{DynSend, DynSync};
use rustc_errors::ErrorGuaranteed;
use rustc_metadata::EncodedMetadata;
use rustc_middle::dep_graph::{WorkProduct, WorkProductId};
+use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::layout::{FnAbiOf, HasTyCtxt, LayoutOf, TyAndLayout};
-use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{Ty, TyCtxt};
use rustc_session::{
config::{self, OutputFilenames, PrintRequest},
@@ -20,10 +23,6 @@ use rustc_span::symbol::Symbol;
use rustc_target::abi::call::FnAbi;
use rustc_target::spec::Target;
-pub use rustc_data_structures::sync::MetadataRef;
-
-use std::any::Any;
-
pub trait BackendTypes {
type Value: CodegenObject;
type Function: CodegenObject;
@@ -117,7 +116,9 @@ pub trait CodegenBackend {
) -> Result<(), ErrorGuaranteed>;
}
-pub trait ExtraBackendMethods: CodegenBackend + WriteBackendMethods + Sized + Send + Sync {
+pub trait ExtraBackendMethods:
+ CodegenBackend + WriteBackendMethods + Sized + Send + Sync + DynSend + DynSync
+{
fn codegen_allocator<'tcx>(
&self,
tcx: TyCtxt<'tcx>,
diff --git a/compiler/rustc_codegen_ssa/src/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs
index 194768d94..853c6934c 100644
--- a/compiler/rustc_codegen_ssa/src/traits/builder.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs
@@ -14,6 +14,7 @@ use crate::mir::operand::OperandRef;
use crate::mir::place::PlaceRef;
use crate::MemFlags;
+use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout};
use rustc_middle::ty::Ty;
use rustc_span::Span;
@@ -72,6 +73,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn invoke(
&mut self,
llty: Self::Type,
+ fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: Self::Value,
args: &[Self::Value],
@@ -272,6 +274,7 @@ pub trait BuilderMethods<'a, 'tcx>:
// These are used by everyone except msvc
fn cleanup_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
+ fn filter_landing_pad(&mut self, pers_fn: Self::Value) -> (Self::Value, Self::Value);
fn resume(&mut self, exn0: Self::Value, exn1: Self::Value);
// These are used only by msvc
@@ -321,6 +324,7 @@ pub trait BuilderMethods<'a, 'tcx>:
fn call(
&mut self,
llty: Self::Type,
+ fn_attrs: Option<&CodegenFnAttrs>,
fn_abi: Option<&FnAbi<'tcx, Ty<'tcx>>>,
llfn: Self::Value,
args: &[Self::Value],
diff --git a/compiler/rustc_codegen_ssa/src/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs
index 32905b079..36d986422 100644
--- a/compiler/rustc_codegen_ssa/src/traits/type_.rs
+++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs
@@ -128,12 +128,16 @@ pub trait LayoutTypeMethods<'tcx>: Backend<'tcx> {
) -> Self::Type;
}
-// For backends that support CFI using type membership (i.e., testing whether a given pointer is
+// For backends that support CFI using type membership (i.e., testing whether a given pointer is
// associated with a type identifier).
pub trait TypeMembershipMethods<'tcx>: Backend<'tcx> {
- fn set_type_metadata(&self, function: Self::Function, typeid: String);
- fn typeid_metadata(&self, typeid: String) -> Self::Value;
- fn set_kcfi_type_metadata(&self, function: Self::Function, typeid: u32);
+ fn add_type_metadata(&self, _function: Self::Function, _typeid: String) {}
+ fn set_type_metadata(&self, _function: Self::Function, _typeid: String) {}
+ fn typeid_metadata(&self, _typeid: String) -> Option<Self::Value> {
+ None
+ }
+ fn add_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
+ fn set_kcfi_type_metadata(&self, _function: Self::Function, _typeid: u32) {}
}
pub trait ArgAbiMethods<'tcx>: HasCodegen<'tcx> {
diff --git a/compiler/rustc_const_eval/Cargo.toml b/compiler/rustc_const_eval/Cargo.toml
index 98ac36c1c..74030a43c 100644
--- a/compiler/rustc_const_eval/Cargo.toml
+++ b/compiler/rustc_const_eval/Cargo.toml
@@ -14,6 +14,7 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_const_eval/messages.ftl b/compiler/rustc_const_eval/messages.ftl
index f6751df44..7d56cf0aa 100644
--- a/compiler/rustc_const_eval/messages.ftl
+++ b/compiler/rustc_const_eval/messages.ftl
@@ -1,40 +1,60 @@
-const_eval_unstable_in_stable =
- const-stable function cannot use `#[feature({$gate})]`
- .unstable_sugg = if it is not part of the public API, make this function unstably const
- .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
+const_eval_interior_mutability_borrow =
+ cannot borrow here, since the borrowed element may contain interior mutability
-const_eval_thread_local_access =
- thread-local statics cannot be accessed at compile-time
+const_eval_interior_mutable_data_refer =
+ {$kind}s cannot refer to interior mutable data
+ .label = this borrow of an interior mutable value may end up in the final value
+ .help = to fix this, the value can be extracted to a separate `static` item and then referenced
+ .teach_note =
+ A constant containing interior mutable data behind a reference can allow you to modify that data.
+ This would make multiple uses of a constant to be able to see different values and allow circumventing
+ the `Send` and `Sync` requirements for shared mutable data, which is unsound.
-const_eval_static_access =
- {$kind}s cannot refer to statics
- .help = consider extracting the value of the `static` to a `const`, and referring to that
- .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
- .teach_help = To fix this, the value can be extracted to a `const` and then used.
+const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
-const_eval_raw_ptr_to_int =
- pointers cannot be cast to integers during const eval
- .note = at compile-time, pointers do not have an integer value
- .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
+const_eval_mut_deref =
+ mutation through a reference is not allowed in {$kind}s
+
+const_eval_non_const_fmt_macro_call =
+ cannot call non-const formatting macro in {$kind}s
+
+const_eval_non_const_fn_call =
+ cannot call non-const fn `{$def_path_str}` in {$kind}s
+
+const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str`
const_eval_raw_ptr_comparison =
pointers cannot be reliably compared during const eval
.note = see issue #53020 <https://github.com/rust-lang/rust/issues/53020> for more information
-const_eval_panic_non_str = argument to `panic!()` in a const context must have type `&str`
+const_eval_raw_ptr_to_int =
+ pointers cannot be cast to integers during const eval
+ .note = at compile-time, pointers do not have an integer value
+ .note2 = avoiding this restriction via `transmute`, `union`, or raw pointers leads to compile-time undefined behavior
-const_eval_mut_deref =
- mutation through a reference is not allowed in {$kind}s
+const_eval_static_access =
+ {$kind}s cannot refer to statics
+ .help = consider extracting the value of the `static` to a `const`, and referring to that
+ .teach_note = `static` and `const` variables can refer to other `const` variables. A `const` variable, however, cannot refer to a `static` variable.
+ .teach_help = To fix this, the value can be extracted to a `const` and then used.
+
+const_eval_thread_local_access =
+ thread-local statics cannot be accessed at compile-time
const_eval_transient_mut_borrow = mutable references are not allowed in {$kind}s
const_eval_transient_mut_borrow_raw = raw mutable references are not allowed in {$kind}s
-const_eval_max_num_nodes_in_const = maximum number of nodes exceeded in constant {$global_const_id}
-
const_eval_unallowed_fn_pointer_call = function pointer calls are not allowed in {$kind}s
-const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
+const_eval_unallowed_heap_allocations =
+ allocations are not allowed in {$kind}s
+ .label = allocation not allowed in {$kind}s
+ .teach_note =
+ The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
+
+const_eval_unallowed_inline_asm =
+ inline assembly is not allowed in {$kind}s
const_eval_unallowed_mutable_refs =
mutable references are not allowed in the final value of {$kind}s
@@ -60,32 +80,12 @@ const_eval_unallowed_mutable_refs_raw =
If you really want global mutable state, try using static mut or a global UnsafeCell.
-const_eval_non_const_fmt_macro_call =
- cannot call non-const formatting macro in {$kind}s
-
-const_eval_non_const_fn_call =
- cannot call non-const fn `{$def_path_str}` in {$kind}s
-
const_eval_unallowed_op_in_const_context =
{$msg}
-const_eval_unallowed_heap_allocations =
- allocations are not allowed in {$kind}s
- .label = allocation not allowed in {$kind}s
- .teach_note =
- The value of statics and constants must be known at compile time, and they live for the entire lifetime of a program. Creating a boxed value allocates memory on the heap at runtime, and therefore cannot be done at compile time.
-
-const_eval_unallowed_inline_asm =
- inline assembly is not allowed in {$kind}s
-
-const_eval_interior_mutable_data_refer =
- {$kind}s cannot refer to interior mutable data
- .label = this borrow of an interior mutable value may end up in the final value
- .help = to fix this, the value can be extracted to a separate `static` item and then referenced
- .teach_note =
- A constant containing interior mutable data behind a reference can allow you to modify that data.
- This would make multiple uses of a constant to be able to see different values and allow circumventing
- the `Send` and `Sync` requirements for shared mutable data, which is unsound.
+const_eval_unstable_const_fn = `{$def_path}` is not yet stable as a const fn
-const_eval_interior_mutability_borrow =
- cannot borrow here, since the borrowed element may contain interior mutability
+const_eval_unstable_in_stable =
+ const-stable function cannot use `#[feature({$gate})]`
+ .unstable_sugg = if it is not part of the public API, make this function unstably const
+ .bypass_sugg = otherwise `#[rustc_allow_const_fn_unstable]` can be used to bypass stability checks
diff --git a/compiler/rustc_const_eval/src/const_eval/error.rs b/compiler/rustc_const_eval/src/const_eval/error.rs
index 0579f7815..c591ff75a 100644
--- a/compiler/rustc_const_eval/src/const_eval/error.rs
+++ b/compiler/rustc_const_eval/src/const_eval/error.rs
@@ -3,7 +3,8 @@ use std::fmt;
use rustc_errors::Diagnostic;
use rustc_middle::mir::AssertKind;
-use rustc_middle::ty::{layout::LayoutError, query::TyCtxtAt, ConstInt};
+use rustc_middle::query::TyCtxtAt;
+use rustc_middle::ty::{layout::LayoutError, ConstInt};
use rustc_span::{Span, Symbol};
use super::InterpCx;
@@ -104,13 +105,13 @@ impl<'tcx> ConstEvalErr<'tcx> {
// Add spans for the stacktrace. Don't print a single-line backtrace though.
if self.stacktrace.len() > 1 {
// Helper closure to print duplicated lines.
- let mut flush_last_line = |last_frame, times| {
+ let mut flush_last_line = |last_frame: Option<(String, _)>, times| {
if let Some((line, span)) = last_frame {
- err.span_note(span, &line);
+ err.span_note(span, line.clone());
// Don't print [... additional calls ...] if the number of lines is small
if times < 3 {
for _ in 0..times {
- err.span_note(span, &line);
+ err.span_note(span, line.clone());
}
} else {
err.span_note(
@@ -169,14 +170,14 @@ impl<'tcx> ConstEvalErr<'tcx> {
// See <https://github.com/rust-lang/rust/pull/63152>.
let mut err = struct_error(tcx, &self.error.to_string());
self.decorate(&mut err, decorate);
- ErrorHandled::Reported(err.emit())
+ ErrorHandled::Reported(err.emit().into())
}
_ => {
// Report as hard error.
let mut err = struct_error(tcx, message);
err.span_label(self.span, self.error.to_string());
self.decorate(&mut err, decorate);
- ErrorHandled::Reported(err.emit())
+ ErrorHandled::Reported(err.emit().into())
}
}
}
diff --git a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
index 4bd6fe199..046d20529 100644
--- a/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/eval_queries.rs
@@ -296,12 +296,12 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
}
let cid = key.value;
- let def = cid.instance.def.with_opt_param();
- let is_static = tcx.is_static(def.did);
+ let def = cid.instance.def.def_id();
+ let is_static = tcx.is_static(def);
let mut ecx = InterpCx::new(
tcx,
- tcx.def_span(def.did),
+ tcx.def_span(def),
key.param_env,
// Statics (and promoteds inside statics) may access other statics, because unlike consts
// they do not have to behave "as if" they were evaluated at runtime.
@@ -368,7 +368,7 @@ pub fn eval_to_allocation_raw_provider<'tcx>(
if matches!(err.error, InterpError::UndefinedBehavior(_)) {
diag.note(NOTE_ON_UNDEFINED_BEHAVIOR_ERROR);
}
- diag.note(&format!(
+ diag.note(format!(
"the raw bytes of the constant ({}",
display_allocation(
*ecx.tcx,
diff --git a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
index 088a824fd..fa8253d5e 100644
--- a/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
+++ b/compiler/rustc_const_eval/src/const_eval/fn_queries.rs
@@ -2,7 +2,7 @@ use rustc_attr as attr;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs
index a5dfd1072..58b5755af 100644
--- a/compiler/rustc_const_eval/src/const_eval/machine.rs
+++ b/compiler/rustc_const_eval/src/const_eval/machine.rs
@@ -375,18 +375,18 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
match instance {
ty::InstanceDef::Item(def) => {
- if ecx.tcx.is_ctfe_mir_available(def.did) {
- Ok(ecx.tcx.mir_for_ctfe_opt_const_arg(def))
- } else if ecx.tcx.def_kind(def.did) == DefKind::AssocConst {
+ if ecx.tcx.is_ctfe_mir_available(def) {
+ Ok(ecx.tcx.mir_for_ctfe(def))
+ } else if ecx.tcx.def_kind(def) == DefKind::AssocConst {
let guar = ecx.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
"This is likely a const item that is missing from its impl",
);
- throw_inval!(AlreadyReported(guar));
+ throw_inval!(AlreadyReported(guar.into()));
} else {
// `find_mir_or_eval_fn` checks that this is a const fn before even calling us,
// so this should be unreachable.
- let path = ecx.tcx.def_path_str(def.did);
+ let path = ecx.tcx.def_path_str(def);
bug!("trying to call extern function `{path}` at compile-time");
}
}
@@ -410,9 +410,9 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir,
// Execution might have wandered off into other crates, so we cannot do a stability-
// sensitive check here. But we can at least rule out functions that are not const
// at all.
- if !ecx.tcx.is_const_fn_raw(def.did) {
+ if !ecx.tcx.is_const_fn_raw(def) {
// allow calling functions inside a trait marked with #[const_trait].
- if !ecx.tcx.is_const_default_method(def.did) {
+ if !ecx.tcx.is_const_default_method(def) {
// We certainly do *not* want to actually call the fn
// though, so be sure we return here.
throw_unsup_format!("calling non-const function `{}`", instance)
diff --git a/compiler/rustc_const_eval/src/const_eval/mod.rs b/compiler/rustc_const_eval/src/const_eval/mod.rs
index 3cdf1e6e3..05be45fef 100644
--- a/compiler/rustc_const_eval/src/const_eval/mod.rs
+++ b/compiler/rustc_const_eval/src/const_eval/mod.rs
@@ -83,7 +83,7 @@ pub(crate) fn eval_to_valtree<'tcx>(
Some(span) => {
tcx.sess.create_err(MaxNumNodesInConstErr { span, global_const_id })
}
- None => tcx.sess.struct_err(&msg),
+ None => tcx.sess.struct_err(msg),
};
diag.emit();
diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
index 4d54c0183..b10f2e9f8 100644
--- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs
+++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs
@@ -337,7 +337,7 @@ fn valtree_into_mplace<'tcx>(
match ty.kind() {
ty::FnDef(_, _) => {
- ecx.write_immediate(Immediate::Uninit, &place.into()).unwrap();
+ // Zero-sized type, nothing to do.
}
ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char => {
let scalar_int = valtree.unwrap_leaf();
diff --git a/compiler/rustc_const_eval/src/interpret/discriminant.rs b/compiler/rustc_const_eval/src/interpret/discriminant.rs
index 557e72124..015a9beab 100644
--- a/compiler/rustc_const_eval/src/interpret/discriminant.rs
+++ b/compiler/rustc_const_eval/src/interpret/discriminant.rs
@@ -211,18 +211,19 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
let variant_index_relative = u32::try_from(variant_index_relative)
.expect("we checked that this fits into a u32");
// Then computing the absolute variant idx should not overflow any more.
- let variant_index = variants_start
- .checked_add(variant_index_relative)
- .expect("overflow computing absolute variant idx");
- let variants_len = op
+ let variant_index = VariantIdx::from_u32(
+ variants_start
+ .checked_add(variant_index_relative)
+ .expect("overflow computing absolute variant idx"),
+ );
+ let variants = op
.layout
.ty
.ty_adt_def()
.expect("tagged layout for non adt")
- .variants()
- .len();
- assert!(usize::try_from(variant_index).unwrap() < variants_len);
- VariantIdx::from_u32(variant_index)
+ .variants();
+ assert!(variant_index < variants.next_index());
+ variant_index
} else {
untagged_variant
}
diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs
index 3e58a58ae..7e9457800 100644
--- a/compiler/rustc_const_eval/src/interpret/eval_context.rs
+++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs
@@ -5,16 +5,15 @@ use std::mem;
use either::{Either, Left, Right};
use rustc_hir::{self as hir, def_id::DefId, definitions::DefPathData};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir;
-use rustc_middle::mir::interpret::{ErrorHandled, InterpError};
+use rustc_middle::mir::interpret::{ErrorHandled, InterpError, ReportedErrorInfo};
+use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::layout::{
self, FnAbiError, FnAbiOfHelpers, FnAbiRequest, LayoutError, LayoutOf, LayoutOfHelpers,
TyAndLayout,
};
-use rustc_middle::ty::{
- self, query::TyCtxtAt, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable,
-};
+use rustc_middle::ty::{self, subst::SubstsRef, ParamEnv, Ty, TyCtxt, TypeFoldable};
use rustc_mir_dataflow::storage::always_storage_live_locals;
use rustc_session::Limit;
use rustc_span::Span;
@@ -132,11 +131,10 @@ pub struct Frame<'mir, 'tcx, Prov: Provenance = AllocId, Extra = ()> {
}
/// What we store about a frame in an interpreter backtrace.
-#[derive(Debug)]
+#[derive(Clone, Debug)]
pub struct FrameInfo<'tcx> {
pub instance: ty::Instance<'tcx>,
pub span: Span,
- pub lint_root: Option<hir::HirId>,
}
#[derive(Clone, Copy, Eq, PartialEq, Debug)] // Miri debug-prints these
@@ -462,16 +460,16 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
instance: ty::InstanceDef<'tcx>,
promoted: Option<mir::Promoted>,
) -> InterpResult<'tcx, &'tcx mir::Body<'tcx>> {
- let def = instance.with_opt_param();
trace!("load mir(instance={:?}, promoted={:?})", instance, promoted);
let body = if let Some(promoted) = promoted {
- &self.tcx.promoted_mir_opt_const_arg(def)[promoted]
+ let def = instance.def_id();
+ &self.tcx.promoted_mir(def)[promoted]
} else {
M::load_mir(self, instance)?
};
// do not continue if typeck errors occurred (can only occur in local crate)
if let Some(err) = body.tainted_by_errors {
- throw_inval!(AlreadyReported(err));
+ throw_inval!(AlreadyReported(ReportedErrorInfo::tainted_by_errors(err)));
}
Ok(body)
}
@@ -496,25 +494,29 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
) -> Result<T, InterpError<'tcx>> {
frame
.instance
- .try_subst_mir_and_normalize_erasing_regions(*self.tcx, self.param_env, value)
+ .try_subst_mir_and_normalize_erasing_regions(
+ *self.tcx,
+ self.param_env,
+ ty::EarlyBinder(value),
+ )
.map_err(|_| err_inval!(TooGeneric))
}
/// The `substs` are assumed to already be in our interpreter "universe" (param_env).
pub(super) fn resolve(
&self,
- def: ty::WithOptConstParam<DefId>,
+ def: DefId,
substs: SubstsRef<'tcx>,
) -> InterpResult<'tcx, ty::Instance<'tcx>> {
trace!("resolve: {:?}, {:#?}", def, substs);
trace!("param_env: {:#?}", self.param_env);
trace!("substs: {:#?}", substs);
- match ty::Instance::resolve_opt_const_arg(*self.tcx, self.param_env, def, substs) {
+ match ty::Instance::resolve(*self.tcx, self.param_env, def, substs) {
Ok(Some(instance)) => Ok(instance),
Ok(None) => throw_inval!(TooGeneric),
// FIXME(eddyb) this could be a bit more specific than `AlreadyReported`.
- Err(error_reported) => throw_inval!(AlreadyReported(error_reported)),
+ Err(error_reported) => throw_inval!(AlreadyReported(error_reported.into())),
}
}
@@ -902,7 +904,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
query(self.tcx.at(span.unwrap_or_else(|| self.cur_span()))).map_err(|err| {
match err {
ErrorHandled::Reported(err) => {
- if let Some(span) = span {
+ if !err.is_tainted_by_errors() && let Some(span) = span {
// To make it easier to figure out where this error comes from, also add a note at the current location.
self.tcx.sess.span_note_without_error(span, "erroneous constant used");
}
@@ -947,10 +949,21 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// This deliberately does *not* honor `requires_caller_location` since it is used for much
// more than just panics.
for frame in stack.iter().rev() {
- let lint_root = frame.lint_root();
- let span = frame.current_span();
-
- frames.push(FrameInfo { span, instance: frame.instance, lint_root });
+ let span = match frame.loc {
+ Left(loc) => {
+ // If the stacktrace passes through MIR-inlined source scopes, add them.
+ let mir::SourceInfo { mut span, scope } = *frame.body.source_info(loc);
+ let mut scope_data = &frame.body.source_scopes[scope];
+ while let Some((instance, call_span)) = scope_data.inlined {
+ frames.push(FrameInfo { span, instance });
+ span = call_span;
+ scope_data = &frame.body.source_scopes[scope_data.parent_scope.unwrap()];
+ }
+ span
+ }
+ Right(span) => span,
+ };
+ frames.push(FrameInfo { span, instance: frame.instance });
}
trace!("generate stacktrace: {:#?}", frames);
frames
diff --git a/compiler/rustc_const_eval/src/interpret/intern.rs b/compiler/rustc_const_eval/src/interpret/intern.rs
index b220d21f6..c2b82ba9b 100644
--- a/compiler/rustc_const_eval/src/interpret/intern.rs
+++ b/compiler/rustc_const_eval/src/interpret/intern.rs
@@ -387,7 +387,7 @@ pub fn intern_const_alloc_recursive<
Err(error) => {
ecx.tcx.sess.delay_span_bug(
ecx.tcx.span,
- &format!(
+ format!(
"error during interning should later cause validation failure: {}",
error
),
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics.rs b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
index 26fb041b4..a77c699c2 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics.rs
@@ -75,7 +75,7 @@ pub(crate) fn eval_nullary_intrinsic<'tcx>(
}
sym::type_id => {
ensure_monomorphic_enough(tcx, tp_ty)?;
- ConstValue::from_u64(tcx.type_id_hash(tp_ty))
+ ConstValue::from_u64(tcx.type_id_hash(tp_ty).as_u64())
}
sym::variant_count => match tp_ty.kind() {
// Correctly handles non-monomorphic calls, so there is no need for ensure_monomorphic_enough.
@@ -286,14 +286,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
sym::write_bytes => {
self.write_bytes_intrinsic(&args[0], &args[1], &args[2])?;
}
- sym::offset => {
- let ptr = self.read_pointer(&args[0])?;
- let offset_count = self.read_target_isize(&args[1])?;
- let pointee_ty = substs.type_at(0);
-
- let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
- self.write_pointer(offset_ptr, dest)?;
- }
sym::arith_offset => {
let ptr = self.read_pointer(&args[0])?;
let offset_count = self.read_target_isize(&args[1])?;
diff --git a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
index 3701eb93e..df5b58100 100644
--- a/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
+++ b/compiler/rustc_const_eval/src/interpret/intrinsics/caller_location.rs
@@ -111,11 +111,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
location
}
- pub(crate) fn location_triple_for_span(&self, mut span: Span) -> (Symbol, u32, u32) {
- // Remove `Inlined` marks as they pollute `expansion_cause`.
- while span.is_inlined() {
- span.remove_mark();
- }
+ pub(crate) fn location_triple_for_span(&self, span: Span) -> (Symbol, u32, u32) {
let topmost = span.ctxt().outer_expn().expansion_cause().unwrap_or(span);
let caller = self.tcx.sess.source_map().lookup_char_pos(topmost.lo());
(
diff --git a/compiler/rustc_const_eval/src/interpret/machine.rs b/compiler/rustc_const_eval/src/interpret/machine.rs
index 0291cca73..b448e3a24 100644
--- a/compiler/rustc_const_eval/src/interpret/machine.rs
+++ b/compiler/rustc_const_eval/src/interpret/machine.rs
@@ -104,7 +104,7 @@ pub trait Machine<'mir, 'tcx>: Sized {
type FrameExtra;
/// Extra data stored in every allocation.
- type AllocExtra: Debug + Clone + 'static;
+ type AllocExtra: Debug + Clone + 'tcx;
/// Type for the bytes of the allocation.
type Bytes: AllocBytes + 'static;
diff --git a/compiler/rustc_const_eval/src/interpret/memory.rs b/compiler/rustc_const_eval/src/interpret/memory.rs
index a3764a7d1..d5b6a581a 100644
--- a/compiler/rustc_const_eval/src/interpret/memory.rs
+++ b/compiler/rustc_const_eval/src/interpret/memory.rs
@@ -215,7 +215,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.allocate_raw_ptr(alloc, kind)
}
- /// This can fail only of `alloc` contains provenance.
+ /// This can fail only if `alloc` contains provenance.
pub fn allocate_raw_ptr(
&mut self,
alloc: Allocation,
@@ -807,9 +807,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
DumpAllocs { ecx: self, allocs }
}
- /// Print leaked memory. Allocations reachable from `static_roots` or a `Global` allocation
- /// are not considered leaked. Leaks whose kind `may_leak()` returns true are not reported.
- pub fn leak_report(&self, static_roots: &[AllocId]) -> usize {
+ /// Find leaked allocations. Allocations reachable from `static_roots` or a `Global` allocation
+ /// are not considered leaked, as well as leaks whose kind's `may_leak()` returns true.
+ pub fn find_leaked_allocations(
+ &self,
+ static_roots: &[AllocId],
+ ) -> Vec<(AllocId, MemoryKind<M::MemoryKind>, Allocation<M::Provenance, M::AllocExtra, M::Bytes>)>
+ {
// Collect the set of allocations that are *reachable* from `Global` allocations.
let reachable = {
let mut reachable = FxHashSet::default();
@@ -833,14 +837,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
};
// All allocations that are *not* `reachable` and *not* `may_leak` are considered leaking.
- let leaks: Vec<_> = self.memory.alloc_map.filter_map_collect(|&id, &(kind, _)| {
- if kind.may_leak() || reachable.contains(&id) { None } else { Some(id) }
- });
- let n = leaks.len();
- if n > 0 {
- eprintln!("The following memory was leaked: {:?}", self.dump_allocs(leaks));
- }
- n
+ self.memory.alloc_map.filter_map_collect(|id, (kind, alloc)| {
+ if kind.may_leak() || reachable.contains(id) {
+ None
+ } else {
+ Some((*id, *kind, alloc.clone()))
+ }
+ })
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/operand.rs b/compiler/rustc_const_eval/src/interpret/operand.rs
index 5310ef0bb..e30af1655 100644
--- a/compiler/rustc_const_eval/src/interpret/operand.rs
+++ b/compiler/rustc_const_eval/src/interpret/operand.rs
@@ -245,6 +245,12 @@ impl<'tcx, Prov: Provenance> ImmTy<'tcx, Prov> {
impl<'tcx, Prov: Provenance> OpTy<'tcx, Prov> {
pub fn len(&self, cx: &impl HasDataLayout) -> InterpResult<'tcx, u64> {
if self.layout.is_unsized() {
+ if matches!(self.op, Operand::Immediate(Immediate::Uninit)) {
+ // Uninit unsized places shouldn't occur. In the interpreter we have them
+ // temporarily for unsized arguments before their value is put in; in ConstProp they
+ // remain uninit and this code can actually be reached.
+ throw_inval!(UninitUnsizedLocal);
+ }
// There are no unsized immediates.
self.assert_mem_place().len(cx)
} else {
@@ -589,7 +595,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
// FIXME(generic_const_exprs): `ConstKind::Expr` should be able to be evaluated
ty::ConstKind::Expr(_) => throw_inval!(TooGeneric),
ty::ConstKind::Error(reported) => {
- throw_inval!(AlreadyReported(reported))
+ throw_inval!(AlreadyReported(reported.into()))
}
ty::ConstKind::Unevaluated(uv) => {
let instance = self.resolve(uv.def, uv.substs)?;
diff --git a/compiler/rustc_const_eval/src/interpret/operator.rs b/compiler/rustc_const_eval/src/interpret/operator.rs
index 4decfe863..7186148da 100644
--- a/compiler/rustc_const_eval/src/interpret/operator.rs
+++ b/compiler/rustc_const_eval/src/interpret/operator.rs
@@ -299,6 +299,30 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Ok((val, false, ty))
}
+ fn binary_ptr_op(
+ &self,
+ bin_op: mir::BinOp,
+ left: &ImmTy<'tcx, M::Provenance>,
+ right: &ImmTy<'tcx, M::Provenance>,
+ ) -> InterpResult<'tcx, (Scalar<M::Provenance>, bool, Ty<'tcx>)> {
+ use rustc_middle::mir::BinOp::*;
+
+ match bin_op {
+ // Pointer ops that are always supported.
+ Offset => {
+ let ptr = left.to_scalar().to_pointer(self)?;
+ let offset_count = right.to_scalar().to_target_isize(self)?;
+ let pointee_ty = left.layout.ty.builtin_deref(true).unwrap().ty;
+
+ let offset_ptr = self.ptr_offset_inbounds(ptr, pointee_ty, offset_count)?;
+ Ok((Scalar::from_maybe_pointer(offset_ptr, self), false, left.layout.ty))
+ }
+
+ // Fall back to machine hook so Miri can support more pointer ops.
+ _ => M::binary_ptr_op(self, bin_op, left, right),
+ }
+ }
+
/// Returns the result of the specified operation, whether it overflowed, and
/// the result type.
pub fn overflowing_binary_op(
@@ -368,7 +392,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
right.layout.ty
);
- M::binary_ptr_op(self, bin_op, left, right)
+ self.binary_ptr_op(bin_op, left, right)
}
_ => span_bug!(
self.cur_span(),
diff --git a/compiler/rustc_const_eval/src/interpret/place.rs b/compiler/rustc_const_eval/src/interpret/place.rs
index 03b09cf83..2a31a59ad 100644
--- a/compiler/rustc_const_eval/src/interpret/place.rs
+++ b/compiler/rustc_const_eval/src/interpret/place.rs
@@ -5,7 +5,7 @@
use either::{Either, Left, Right};
use rustc_ast::Mutability;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::mir;
use rustc_middle::ty;
use rustc_middle::ty::layout::{LayoutOf, TyAndLayout};
diff --git a/compiler/rustc_const_eval/src/interpret/step.rs b/compiler/rustc_const_eval/src/interpret/step.rs
index 9a366364e..1e60a1e72 100644
--- a/compiler/rustc_const_eval/src/interpret/step.rs
+++ b/compiler/rustc_const_eval/src/interpret/step.rs
@@ -113,8 +113,14 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
Intrinsic(box intrinsic) => self.emulate_nondiverging_intrinsic(intrinsic)?,
- // Statements we do not track.
- PlaceMention(..) | AscribeUserType(..) => {}
+ // Evaluate the place expression, without reading from it.
+ PlaceMention(box place) => {
+ let _ = self.eval_place(*place)?;
+ }
+
+ // This exists purely to guide borrowck lifetime inference, and does not have
+ // an operational effect.
+ AscribeUserType(..) => {}
// Currently, Miri discards Coverage statements. Coverage statements are only injected
// via an optional compile time MIR pass and have no side effects. Since Coverage
@@ -280,20 +286,23 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
self.write_immediate(*val, &dest)?;
}
- NullaryOp(null_op, ty) => {
+ NullaryOp(ref null_op, ty) => {
let ty = self.subst_from_current_frame_and_normalize_erasing_regions(ty)?;
let layout = self.layout_of(ty)?;
- if layout.is_unsized() {
+ if let mir::NullOp::SizeOf | mir::NullOp::AlignOf = null_op && layout.is_unsized() {
// FIXME: This should be a span_bug (#80742)
self.tcx.sess.delay_span_bug(
self.frame().current_span(),
- &format!("Nullary MIR operator called for unsized type {}", ty),
+ format!("{null_op:?} MIR operator called for unsized type {ty}"),
);
throw_inval!(SizeOfUnsizedType(ty));
}
let val = match null_op {
mir::NullOp::SizeOf => layout.size.bytes(),
mir::NullOp::AlignOf => layout.align.abi.bytes(),
+ mir::NullOp::OffsetOf(fields) => {
+ layout.offset_of_subfield(self, fields.iter().map(|f| f.index())).bytes()
+ }
};
self.write_scalar(Scalar::from_target_usize(val, self), &dest)?;
}
diff --git a/compiler/rustc_const_eval/src/interpret/terminator.rs b/compiler/rustc_const_eval/src/interpret/terminator.rs
index a07702f7d..586e8f063 100644
--- a/compiler/rustc_const_eval/src/interpret/terminator.rs
+++ b/compiler/rustc_const_eval/src/interpret/terminator.rs
@@ -83,8 +83,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
(fn_val, self.fn_abi_of_fn_ptr(fn_sig_binder, extra_args)?, false)
}
ty::FnDef(def_id, substs) => {
- let instance =
- self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?;
+ let instance = self.resolve(def_id, substs)?;
(
FnVal::Instance(instance),
self.fn_abi_of_instance(instance, extra_args)?,
@@ -115,7 +114,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
}
}
- Drop { place, target, unwind } => {
+ Drop { place, target, unwind, replace: _ } => {
let frame = self.frame();
let ty = place.ty(&frame.body.local_decls, *self.tcx).ty;
let ty = self.subst_from_frame_and_normalize_erasing_regions(frame, ty)?;
diff --git a/compiler/rustc_const_eval/src/interpret/util.rs b/compiler/rustc_const_eval/src/interpret/util.rs
index bf2b4ee69..22bdd4d2c 100644
--- a/compiler/rustc_const_eval/src/interpret/util.rs
+++ b/compiler/rustc_const_eval/src/interpret/util.rs
@@ -14,7 +14,7 @@ where
T: TypeVisitable<TyCtxt<'tcx>>,
{
debug!("ensure_monomorphic_enough: ty={:?}", ty);
- if !ty.needs_subst() {
+ if !ty.has_param() {
return Ok(());
}
@@ -27,7 +27,7 @@ where
type BreakTy = FoundParam;
fn visit_ty(&mut self, ty: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
- if !ty.needs_subst() {
+ if !ty.has_param() {
return ControlFlow::Continue(());
}
@@ -36,7 +36,7 @@ where
ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, ..)
| ty::FnDef(def_id, substs) => {
- let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+ let instance = ty::InstanceDef::Item(def_id);
let unused_params = self.tcx.unused_generic_params(instance);
for (index, subst) in substs.into_iter().enumerate() {
let index = index
@@ -46,7 +46,7 @@ where
// are used and require substitution.
// Just in case there are closures or generators within this subst,
// recurse.
- if unused_params.is_used(index) && subst.needs_subst() {
+ if unused_params.is_used(index) && subst.has_param() {
return subst.visit_with(self);
}
}
diff --git a/compiler/rustc_const_eval/src/interpret/validity.rs b/compiler/rustc_const_eval/src/interpret/validity.rs
index 93b5273e1..01b772899 100644
--- a/compiler/rustc_const_eval/src/interpret/validity.rs
+++ b/compiler/rustc_const_eval/src/interpret/validity.rs
@@ -38,16 +38,14 @@ macro_rules! throw_validation_failure {
msg.push_str(", but expected ");
write!(&mut msg, $($expected_fmt)*).unwrap();
)?
- let path = rustc_middle::ty::print::with_no_trimmed_paths!({
- let where_ = &$where;
- if !where_.is_empty() {
- let mut path = String::new();
- write_path(&mut path, where_);
- Some(path)
- } else {
- None
- }
- });
+ let where_ = &$where;
+ let path = if !where_.is_empty() {
+ let mut path = String::new();
+ write_path(&mut path, where_);
+ Some(path)
+ } else {
+ None
+ };
throw_ub!(ValidationFailure { path, msg })
}};
}
@@ -784,7 +782,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
Abi::Scalar(scalar_layout) => {
if !scalar_layout.is_uninit_valid() {
// There is something to check here.
- let scalar = self.read_scalar(op, "initiailized scalar value")?;
+ let scalar = self.read_scalar(op, "initialized scalar value")?;
self.visit_scalar(scalar, scalar_layout)?;
}
}
@@ -794,7 +792,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M>
// the other must be init.
if !a_layout.is_uninit_valid() && !b_layout.is_uninit_valid() {
let (a, b) =
- self.read_immediate(op, "initiailized scalar value")?.to_scalar_pair();
+ self.read_immediate(op, "initialized scalar value")?.to_scalar_pair();
self.visit_scalar(a, a_layout)?;
self.visit_scalar(b, b_layout)?;
}
diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs
index 5ab389d04..c36282d5e 100644
--- a/compiler/rustc_const_eval/src/lib.rs
+++ b/compiler/rustc_const_eval/src/lib.rs
@@ -34,9 +34,9 @@ pub mod transform;
pub mod util;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
+use rustc_middle::query::Providers;
use rustc_middle::ty;
-use rustc_middle::ty::query::Providers;
fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
index 55080d94f..57d939747 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs
@@ -556,7 +556,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
Rvalue::Cast(_, _, _) => {}
- Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
+ Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(_), _) => {}
Rvalue::ShallowInitBox(_, _) => {}
Rvalue::UnaryOp(_, operand) => {
@@ -872,7 +872,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
debug!("Resolving ({:?}) -> {:?}", callee, instance);
if let Ok(Some(func)) = instance {
if let InstanceDef::Item(def) = func.def {
- callee = def.did;
+ callee = def;
}
}
}
@@ -942,7 +942,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == gate)
};
let feature_gate_declared = gate_declared(gate);
- let implied_gate_declared = implied_by.map(gate_declared).unwrap_or(false);
+ let implied_gate_declared = implied_by.is_some_and(gate_declared);
if !feature_gate_declared && !implied_gate_declared {
self.check_op(ops::FnCallUnstable(callee, Some(gate)));
return;
@@ -969,7 +969,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// have no `rustc_const_stable` attributes to be const-unstable as well. This
// should be fixed later.
let callee_is_unstable_unmarked = tcx.lookup_const_stability(callee).is_none()
- && tcx.lookup_stability(callee).map_or(false, |s| s.is_unstable());
+ && tcx.lookup_stability(callee).is_some_and(|s| s.is_unstable());
if callee_is_unstable_unmarked {
trace!("callee_is_unstable_unmarked");
// We do not use `const` modifiers for intrinsic "functions", as intrinsics are
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
index 0e4501922..8ebfee887 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs
@@ -139,5 +139,5 @@ fn is_parent_const_stable_trait(tcx: TyCtxt<'_>, def_id: DefId) -> bool {
return false;
}
- tcx.lookup_const_stability(parent.owner).map_or(false, |stab| stab.is_const_stable())
+ tcx.lookup_const_stability(parent.owner).is_some_and(|stab| stab.is_const_stable())
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
index c0f5b3725..21f3c2c89 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs
@@ -14,6 +14,7 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{suggest_constraining_type_param, Adt, Closure, FnDef, FnPtr, Param, Ty};
use rustc_middle::ty::{Binder, TraitRef};
+use rustc_middle::util::{call_kind, CallDesugaringKind, CallKind};
use rustc_session::parse::feature_err;
use rustc_span::symbol::sym;
use rustc_span::{BytePos, Pos, Span, Symbol};
@@ -21,7 +22,6 @@ use rustc_trait_selection::traits::SelectionContext;
use super::ConstCx;
use crate::errors;
-use crate::util::{call_kind, CallDesugaringKind, CallKind};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum Status {
@@ -77,7 +77,7 @@ impl<'tcx> NonConstOp<'tcx> for FloatingPointOp {
&ccx.tcx.sess.parse_sess,
sym::const_fn_floating_point_arithmetic,
span,
- &format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
+ format!("floating point arithmetic is not allowed in {}s", ccx.const_kind()),
)
}
}
@@ -184,6 +184,9 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
CallDesugaringKind::TryBlockFromOutput => {
error!("`try` block cannot convert `{}` to the result in {}s")
}
+ CallDesugaringKind::Await => {
+ error!("cannot convert `{}` into a future in {}s")
+ }
};
diag_trait(&mut err, self_ty, kind.trait_def_id(tcx));
@@ -208,13 +211,13 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
err.span_note(span, "function defined here, but it is not `const`");
}
FnPtr(..) => {
- err.note(&format!(
+ err.note(format!(
"function pointers need an RFC before allowed to be called in {}s",
ccx.const_kind()
));
}
Closure(..) => {
- err.note(&format!(
+ err.note(format!(
"closures need an RFC before allowed to be called in {}s",
ccx.const_kind()
));
@@ -286,7 +289,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
ccx.const_kind()
);
- err.note(&format!("attempting to deref into `{}`", deref_target_ty));
+ err.note(format!("attempting to deref into `{}`", deref_target_ty));
// Check first whether the source is accessible (issue #87060)
if tcx.sess.source_map().is_span_accessible(deref_target) {
@@ -296,7 +299,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
diag_trait(&mut err, self_ty, tcx.require_lang_item(LangItem::Deref, Some(span)));
err
}
- _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentV1Methods) => ccx
+ _ if tcx.opt_parent(callee) == tcx.get_diagnostic_item(sym::ArgumentMethods) => ccx
.tcx
.sess
.create_err(errors::NonConstFmtMacroCall { span, kind: ccx.const_kind() }),
@@ -307,14 +310,14 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> {
}),
};
- err.note(&format!(
+ err.note(format!(
"calls in {}s are limited to constant functions, \
tuple structs and tuple variants",
ccx.const_kind(),
));
if let Some(feature) = feature && ccx.tcx.sess.is_nightly_build() {
- err.help(&format!(
+ err.help(format!(
"add `#![feature({})]` to the crate attributes to enable",
feature,
));
@@ -351,7 +354,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallUnstable {
err.help("const-stable functions can only call other const-stable functions");
} else if ccx.tcx.sess.is_nightly_build() {
if let Some(feature) = feature {
- err.help(&format!(
+ err.help(format!(
"add `#![feature({})]` to the crate attributes to enable",
feature
));
@@ -610,10 +613,11 @@ pub struct RawPtrComparison;
impl<'tcx> NonConstOp<'tcx> for RawPtrComparison {
fn build_error(
&self,
- _: &ConstCx<'_, 'tcx>,
+ ccx: &ConstCx<'_, 'tcx>,
span: Span,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- span_bug!(span, "raw ptr comparison should already be caught in the trait system");
+ // FIXME(const_trait_impl): revert to span_bug?
+ ccx.tcx.sess.create_err(errors::RawPtrComparisonErr { span })
}
}
@@ -633,7 +637,7 @@ impl<'tcx> NonConstOp<'tcx> for RawMutPtrDeref {
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
- &format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
+ format!("dereferencing raw mutable pointers in {}s is unstable", ccx.const_kind(),),
)
}
}
@@ -720,7 +724,7 @@ pub mod ty {
&ccx.tcx.sess.parse_sess,
sym::const_mut_refs,
span,
- &format!("mutable references are not allowed in {}s", ccx.const_kind()),
+ format!("mutable references are not allowed in {}s", ccx.const_kind()),
)
}
}
diff --git a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
index 6758cba2e..1da205790 100644
--- a/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
+++ b/compiler/rustc_const_eval/src/transform/check_consts/qualifs.rs
@@ -157,7 +157,7 @@ impl Qualif for NeedsNonConstDrop {
cx.tcx,
ObligationCause::dummy_with_span(cx.body.span),
cx.param_env,
- ty::Binder::dummy(cx.tcx.at(cx.body.span).mk_trait_ref(LangItem::Destruct, [ty]))
+ ty::TraitRef::from_lang_item(cx.tcx, LangItem::Destruct, cx.body.span, [ty])
.with_constness(ty::BoundConstness::ConstIfConst),
);
@@ -364,9 +364,8 @@ where
assert!(promoted.is_none() || Q::ALLOW_PROMOTED);
// Don't peek inside trait associated constants.
- if promoted.is_none() && cx.tcx.trait_of_item(def.did).is_none() {
- assert_eq!(def.const_param_did, None, "expected associated const: {def:?}");
- let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def.did);
+ if promoted.is_none() && cx.tcx.trait_of_item(def).is_none() {
+ let qualifs = cx.tcx.at(constant.span).mir_const_qualif(def);
if !Q::in_qualifs(&qualifs) {
return false;
diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs
index 7919aed09..0e2d9ee8f 100644
--- a/compiler/rustc_const_eval/src/transform/promote_consts.rs
+++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs
@@ -21,7 +21,7 @@ use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, List, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use std::cell::Cell;
use std::{cmp, iter, mem};
@@ -514,6 +514,7 @@ impl<'tcx> Validator<'_, 'tcx> {
Rvalue::NullaryOp(op, _) => match op {
NullOp::SizeOf => {}
NullOp::AlignOf => {}
+ NullOp::OffsetOf(_) => {}
},
Rvalue::ShallowInitBox(_, _) => return Err(Unpromotable),
@@ -828,7 +829,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
}
fn promote_candidate(mut self, candidate: Candidate, next_promoted_id: usize) -> Body<'tcx> {
- let def = self.source.source.with_opt_param();
+ let def = self.source.source.def_id();
let mut rvalue = {
let promoted = &mut self.promoted;
let promoted_id = Promoted::new(next_promoted_id);
@@ -836,7 +837,7 @@ impl<'a, 'tcx> Promoter<'a, 'tcx> {
let mut promoted_operand = |ty, span| {
promoted.span = span;
promoted.local_decls[RETURN_PLACE] = LocalDecl::new(ty, span);
- let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def.did));
+ let substs = tcx.erase_regions(InternalSubsts::identity_for_item(tcx, def));
let uneval = mir::UnevaluatedConst { def, substs, promoted: Some(promoted_id) };
Operand::Constant(Box::new(Constant {
diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs
index d4bed9738..3c350e25b 100644
--- a/compiler/rustc_const_eval/src/transform/validate.rs
+++ b/compiler/rustc_const_eval/src/transform/validate.rs
@@ -2,15 +2,16 @@
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_infer::traits::Reveal;
use rustc_middle::mir::interpret::Scalar;
use rustc_middle::mir::visit::{NonUseContext, PlaceContext, Visitor};
use rustc_middle::mir::{
traversal, BasicBlock, BinOp, Body, BorrowKind, CastKind, CopyNonOverlapping, Local, Location,
- MirPass, MirPhase, NonDivergingIntrinsic, Operand, Place, PlaceElem, PlaceRef, ProjectionElem,
- RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind, Terminator,
- TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents, START_BLOCK,
+ MirPass, MirPhase, NonDivergingIntrinsic, NullOp, Operand, Place, PlaceElem, PlaceRef,
+ ProjectionElem, RetagKind, RuntimePhase, Rvalue, SourceScope, Statement, StatementKind,
+ Terminator, TerminatorKind, UnOp, UnwindAction, VarDebugInfo, VarDebugInfoContents,
+ START_BLOCK,
};
use rustc_middle::ty::{self, InstanceDef, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_mir_dataflow::impls::MaybeStorageLive;
@@ -106,7 +107,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// occurred.
self.tcx.sess.diagnostic().delay_span_bug(
span,
- &format!(
+ format!(
"broken MIR in {:?} ({}) at {:?}:\n{}",
self.body.source.instance,
self.when,
@@ -163,7 +164,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
if let Some(root) = post_contract_node.get(&bb) {
break *root;
}
- let parent = doms.immediate_dominator(bb);
+ let parent = doms.immediate_dominator(bb).unwrap();
dom_path.push(bb);
if !self.body.basic_blocks[parent].is_cleanup {
break bb;
@@ -262,7 +263,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
// We sometimes have to use `defining_opaque_types` for subtyping
// to succeed here and figuring out how exactly that should work
// is annoying. It is harmless enough to just not validate anything
- // in that case. We still check this after analysis as all opque
+ // in that case. We still check this after analysis as all opaque
// types have been revealed at this point.
if (src, dest).has_opaque_types() {
return true;
@@ -447,7 +448,15 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
};
match debuginfo.value {
VarDebugInfoContents::Const(_) => {}
- VarDebugInfoContents::Place(place) => check_place(place),
+ VarDebugInfoContents::Place(place) => {
+ check_place(place);
+ if debuginfo.references != 0 && place.projection.last() == Some(&PlaceElem::Deref) {
+ self.fail(
+ START_BLOCK.start_location(),
+ format!("debuginfo {:?}, has both ref and deref", debuginfo),
+ );
+ }
+ }
VarDebugInfoContents::Composite { ty, ref fragments } => {
for f in fragments {
check_place(f.contents);
@@ -711,10 +720,54 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
+ Rvalue::NullaryOp(NullOp::OffsetOf(fields), container) => {
+ let fail_out_of_bounds = |this: &Self, location, field, ty| {
+ this.fail(location, format!("Out of bounds field {field:?} for {ty:?}"));
+ };
+
+ let mut current_ty = *container;
+
+ for field in fields.iter() {
+ match current_ty.kind() {
+ ty::Tuple(fields) => {
+ let Some(&f_ty) = fields.get(field.as_usize()) else {
+ fail_out_of_bounds(self, location, field, current_ty);
+ return;
+ };
+
+ current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
+ }
+ ty::Adt(adt_def, substs) => {
+ if adt_def.is_enum() {
+ self.fail(
+ location,
+ format!("Cannot get field offset from enum {current_ty:?}"),
+ );
+ return;
+ }
+
+ let Some(field) = adt_def.non_enum_variant().fields.get(field) else {
+ fail_out_of_bounds(self, location, field, current_ty);
+ return;
+ };
+
+ let f_ty = field.ty(self.tcx, substs);
+ current_ty = self.tcx.normalize_erasing_regions(self.param_env, f_ty);
+ }
+ _ => {
+ self.fail(
+ location,
+ format!("Cannot get field offset from non-adt type {current_ty:?}"),
+ );
+ return;
+ }
+ }
+ }
+ }
Rvalue::Repeat(_, _)
| Rvalue::ThreadLocalRef(_)
| Rvalue::AddressOf(_, _)
- | Rvalue::NullaryOp(_, _)
+ | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _)
| Rvalue::Discriminant(_) => {}
}
self.super_rvalue(rvalue, location);
@@ -757,14 +810,6 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
}
}
}
- StatementKind::PlaceMention(..) => {
- if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
- self.fail(
- location,
- "`PlaceMention` should have been removed after drop lowering phase",
- );
- }
- }
StatementKind::AscribeUserType(..) => {
if self.mir_phase >= MirPhase::Runtime(RuntimePhase::Initial) {
self.fail(
@@ -874,6 +919,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
StatementKind::StorageDead(_)
| StatementKind::Coverage(_)
| StatementKind::ConstEvalCounter
+ | StatementKind::PlaceMention(..)
| StatementKind::Nop => {}
}
@@ -1056,7 +1102,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
if self.body.source_scopes.get(scope).is_none() {
self.tcx.sess.diagnostic().delay_span_bug(
self.body.span,
- &format!(
+ format!(
"broken MIR in {:?} ({}):\ninvalid source scope {:?}",
self.body.source.instance, self.when, scope,
),
diff --git a/compiler/rustc_const_eval/src/util/compare_types.rs b/compiler/rustc_const_eval/src/util/compare_types.rs
index f5f3d5de6..d6a2ffb75 100644
--- a/compiler/rustc_const_eval/src/util/compare_types.rs
+++ b/compiler/rustc_const_eval/src/util/compare_types.rs
@@ -3,8 +3,8 @@
//! FIXME: Move this to a more general place. The utility of this extends to
//! other areas of the compiler as well.
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCause;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_trait_selection::traits::ObligationCtxt;
diff --git a/compiler/rustc_const_eval/src/util/mod.rs b/compiler/rustc_const_eval/src/util/mod.rs
index c0aabd77c..7641f5607 100644
--- a/compiler/rustc_const_eval/src/util/mod.rs
+++ b/compiler/rustc_const_eval/src/util/mod.rs
@@ -1,14 +1,9 @@
mod alignment;
-mod call_kind;
mod check_validity_requirement;
-pub mod collect_writes;
mod compare_types;
-mod find_self_call;
mod type_name;
pub use self::alignment::is_disaligned;
-pub use self::call_kind::{call_kind, CallDesugaringKind, CallKind};
pub use self::check_validity_requirement::check_validity_requirement;
pub use self::compare_types::{is_equal_up_to_subtyping, is_subtype};
-pub use self::find_self_call::find_self_call;
pub use self::type_name::type_name;
diff --git a/compiler/rustc_const_eval/src/util/type_name.rs b/compiler/rustc_const_eval/src/util/type_name.rs
index 4e80a2851..11ad5b49d 100644
--- a/compiler/rustc_const_eval/src/util/type_name.rs
+++ b/compiler/rustc_const_eval/src/util/type_name.rs
@@ -58,11 +58,12 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> {
// Types with identity (print the module path).
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
ty::Foreign(def_id) => self.print_def_path(def_id, &[]),
+ ty::Alias(ty::Inherent, _) => bug!("type_name: unexpected inherent projection"),
ty::GeneratorWitness(_) => bug!("type_name: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("type_name: unexpected `GeneratorWitnessMIR`"),
}
diff --git a/compiler/rustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml
index 2102f09c5..78f73d193 100644
--- a/compiler/rustc_data_structures/Cargo.toml
+++ b/compiler/rustc_data_structures/Cargo.toml
@@ -16,18 +16,17 @@ libc = "0.2"
measureme = "10.0.0"
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
+rustc_arena = { path = "../rustc_arena" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc-hash = "1.1.0"
rustc_index = { path = "../rustc_index", package = "rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
-serde_json = "1.0.59"
smallvec = { version = "1.8.1", features = [
"const_generics",
"union",
"may_dangle",
] }
-stable_deref_trait = "1.0.0"
stacker = "0.1.15"
tempfile = "3.2"
thin-vec = "0.2.12"
@@ -39,7 +38,7 @@ itertools = "0.10.1"
version = "0.11"
[target.'cfg(windows)'.dependencies.windows]
-version = "0.46.0"
+version = "0.48.0"
features = [
"Win32_Foundation",
"Win32_Storage_FileSystem",
diff --git a/compiler/rustc_data_structures/src/aligned.rs b/compiler/rustc_data_structures/src/aligned.rs
new file mode 100644
index 000000000..0e5ecfd9b
--- /dev/null
+++ b/compiler/rustc_data_structures/src/aligned.rs
@@ -0,0 +1,33 @@
+use std::ptr::Alignment;
+
+/// Returns the ABI-required minimum alignment of a type in bytes.
+///
+/// This is equivalent to [`mem::align_of`], but also works for some unsized
+/// types (e.g. slices or rustc's `List`s).
+///
+/// [`mem::align_of`]: std::mem::align_of
+pub const fn align_of<T: ?Sized + Aligned>() -> Alignment {
+ T::ALIGN
+}
+
+/// A type with a statically known alignment.
+///
+/// # Safety
+///
+/// `Self::ALIGN` must be equal to the alignment of `Self`. For sized types it
+/// is [`mem::align_of<Self>()`], for unsized types it depends on the type, for
+/// example `[T]` has alignment of `T`.
+///
+/// [`mem::align_of<Self>()`]: std::mem::align_of
+pub unsafe trait Aligned {
+ /// Alignment of `Self`.
+ const ALIGN: Alignment;
+}
+
+unsafe impl<T> Aligned for T {
+ const ALIGN: Alignment = Alignment::of::<Self>();
+}
+
+unsafe impl<T> Aligned for [T] {
+ const ALIGN: Alignment = Alignment::of::<T>();
+}
diff --git a/compiler/rustc_data_structures/src/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs
index b6e866f15..9995c0834 100644
--- a/compiler/rustc_data_structures/src/fingerprint.rs
+++ b/compiler/rustc_data_structures/src/fingerprint.rs
@@ -1,4 +1,4 @@
-use crate::stable_hasher;
+use crate::stable_hasher::{Hash64, StableHasher, StableHasherResult};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::hash::{Hash, Hasher};
@@ -9,32 +9,49 @@ mod tests;
#[repr(C)]
pub struct Fingerprint(u64, u64);
-impl Fingerprint {
- pub const ZERO: Fingerprint = Fingerprint(0, 0);
+pub trait FingerprintComponent {
+ fn as_u64(&self) -> u64;
+}
+impl FingerprintComponent for Hash64 {
#[inline]
- pub fn new(_0: u64, _1: u64) -> Fingerprint {
- Fingerprint(_0, _1)
+ fn as_u64(&self) -> u64 {
+ Hash64::as_u64(*self)
}
+}
+impl FingerprintComponent for u64 {
#[inline]
- pub fn from_smaller_hash(hash: u64) -> Fingerprint {
- Fingerprint(hash, hash)
+ fn as_u64(&self) -> u64 {
+ *self
+ }
+}
+
+impl Fingerprint {
+ pub const ZERO: Fingerprint = Fingerprint(0, 0);
+
+ #[inline]
+ pub fn new<A, B>(_0: A, _1: B) -> Fingerprint
+ where
+ A: FingerprintComponent,
+ B: FingerprintComponent,
+ {
+ Fingerprint(_0.as_u64(), _1.as_u64())
}
#[inline]
- pub fn to_smaller_hash(&self) -> u64 {
+ pub fn to_smaller_hash(&self) -> Hash64 {
// Even though both halves of the fingerprint are expected to be good
// quality hash values, let's still combine the two values because the
// Fingerprints in DefPathHash have the StableCrateId portion which is
// the same for all DefPathHashes from the same crate. Combining the
// two halves makes sure we get a good quality hash in such cases too.
- self.0.wrapping_mul(3).wrapping_add(self.1)
+ Hash64::new(self.0.wrapping_mul(3).wrapping_add(self.1))
}
#[inline]
- pub fn as_value(&self) -> (u64, u64) {
- (self.0, self.1)
+ pub fn split(&self) -> (Hash64, Hash64) {
+ (Hash64::new(self.0), Hash64::new(self.1))
}
#[inline]
@@ -47,6 +64,11 @@ impl Fingerprint {
)
}
+ #[inline]
+ pub(crate) fn as_u128(self) -> u128 {
+ u128::from(self.1) << 64 | u128::from(self.0)
+ }
+
// Combines two hashes in an order independent way. Make sure this is what
// you want.
#[inline]
@@ -131,9 +153,9 @@ impl FingerprintHasher for crate::unhash::Unhasher {
}
}
-impl stable_hasher::StableHasherResult for Fingerprint {
+impl StableHasherResult for Fingerprint {
#[inline]
- fn finish(hasher: stable_hasher::StableHasher) -> Self {
+ fn finish(hasher: StableHasher) -> Self {
let (_0, _1) = hasher.finalize();
Fingerprint(_0, _1)
}
diff --git a/compiler/rustc_data_structures/src/fingerprint/tests.rs b/compiler/rustc_data_structures/src/fingerprint/tests.rs
index 9b0783e33..09ec2622a 100644
--- a/compiler/rustc_data_structures/src/fingerprint/tests.rs
+++ b/compiler/rustc_data_structures/src/fingerprint/tests.rs
@@ -1,11 +1,12 @@
use super::*;
+use crate::stable_hasher::Hash64;
// Check that `combine_commutative` is order independent.
#[test]
fn combine_commutative_is_order_independent() {
- let a = Fingerprint::new(0xf6622fb349898b06, 0x70be9377b2f9c610);
- let b = Fingerprint::new(0xa9562bf5a2a5303c, 0x67d9b6c82034f13d);
- let c = Fingerprint::new(0x0d013a27811dbbc3, 0x9a3f7b3d9142ec43);
+ let a = Fingerprint::new(Hash64::new(0xf6622fb349898b06), Hash64::new(0x70be9377b2f9c610));
+ let b = Fingerprint::new(Hash64::new(0xa9562bf5a2a5303c), Hash64::new(0x67d9b6c82034f13d));
+ let c = Fingerprint::new(Hash64::new(0x0d013a27811dbbc3), Hash64::new(0x9a3f7b3d9142ec43));
let permutations = [(a, b, c), (a, c, b), (b, a, c), (b, c, a), (c, a, b), (c, b, a)];
let f = a.combine_commutative(b).combine_commutative(c);
for p in &permutations {
diff --git a/compiler/rustc_data_structures/src/functor.rs b/compiler/rustc_data_structures/src/functor.rs
index 28fcf80b3..e3fcaccb1 100644
--- a/compiler/rustc_data_structures/src/functor.rs
+++ b/compiler/rustc_data_structures/src/functor.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use std::{mem, rc::Rc, sync::Arc};
pub trait IdFunctor: Sized {
diff --git a/compiler/rustc_data_structures/src/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
index 0df9dc112..a5db14d91 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/mod.rs
@@ -10,7 +10,8 @@
//! <https://www.cs.princeton.edu/courses/archive/spr03/cs423/download/dominators.pdf>
use super::ControlFlowGraph;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
+
use std::cmp::Ordering;
#[cfg(test)]
@@ -25,7 +26,7 @@ rustc_index::newtype_index! {
struct PreorderIndex {}
}
-pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
+pub fn dominators<G: ControlFlowGraph>(graph: &G) -> Dominators<G::Node> {
// compute the post order index (rank) for each node
let mut post_order_rank = IndexVec::from_elem_n(0, graph.num_nodes());
@@ -108,28 +109,27 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
// they have been placed in the bucket.
//
// We compute a partial set of immediate dominators here.
- let z = parent[w];
- for &v in bucket[z].iter() {
+ for &v in bucket[w].iter() {
// This uses the result of Lemma 5 from section 2 from the original
// 1979 paper, to compute either the immediate or relative dominator
// for a given vertex v.
//
// eval returns a vertex y, for which semi[y] is minimum among
- // vertices semi[v] +> y *> v. Note that semi[v] = z as we're in the
- // z bucket.
+ // vertices semi[v] +> y *> v. Note that semi[v] = w as we're in the
+ // w bucket.
//
// Given such a vertex y, semi[y] <= semi[v] and idom[y] = idom[v].
// If semi[y] = semi[v], though, idom[v] = semi[v].
//
// Using this, we can either set idom[v] to be:
- // * semi[v] (i.e. z), if semi[y] is z
+ // * semi[v] (i.e. w), if semi[y] is w
// * idom[y], otherwise
//
// We don't directly set to idom[y] though as it's not necessarily
// known yet. The second preorder traversal will cleanup by updating
// the idom for any that were missed in this pass.
let y = eval(&mut parent, lastlinked, &semi, &mut label, v);
- idom[v] = if semi[y] < z { y } else { z };
+ idom[v] = if semi[y] < w { y } else { w };
}
// This loop computes the semi[w] for w.
@@ -212,10 +212,11 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
// If we don't yet know the idom directly, then push this vertex into
// our semidominator's bucket, where it will get processed at a later
// stage to compute its immediate dominator.
- if parent[w] != semi[w] {
+ let z = parent[w];
+ if z != semi[w] {
bucket[semi[w]].push(w);
} else {
- idom[w] = parent[w];
+ idom[w] = z;
}
// Optimization: We share the parent array between processed and not
@@ -241,7 +242,12 @@ pub fn dominators<G: ControlFlowGraph>(graph: G) -> Dominators<G::Node> {
immediate_dominators[*node] = Some(pre_order_to_real[idom[idx]]);
}
- Dominators { post_order_rank, immediate_dominators }
+ let start_node = graph.start_node();
+ immediate_dominators[start_node] = None;
+
+ let time = compute_access_time(start_node, &immediate_dominators);
+
+ Dominators { start_node, post_order_rank, immediate_dominators, time }
}
/// Evaluate the link-eval virtual forest, providing the currently minimum semi
@@ -307,34 +313,31 @@ fn compress(
/// Tracks the list of dominators for each node.
#[derive(Clone, Debug)]
pub struct Dominators<N: Idx> {
+ start_node: N,
post_order_rank: IndexVec<N, usize>,
// Even though we track only the immediate dominator of each node, it's
// possible to get its full list of dominators by looking up the dominator
// of each dominator. (See the `impl Iterator for Iter` definition).
immediate_dominators: IndexVec<N, Option<N>>,
+ time: IndexVec<N, Time>,
}
impl<Node: Idx> Dominators<Node> {
- /// Whether the given Node has an immediate dominator.
+ /// Returns true if node is reachable from the start node.
pub fn is_reachable(&self, node: Node) -> bool {
- self.immediate_dominators[node].is_some()
+ node == self.start_node || self.immediate_dominators[node].is_some()
}
- pub fn immediate_dominator(&self, node: Node) -> Node {
- assert!(self.is_reachable(node), "node {node:?} is not reachable");
- self.immediate_dominators[node].unwrap()
+ /// Returns the immediate dominator of node, if any.
+ pub fn immediate_dominator(&self, node: Node) -> Option<Node> {
+ self.immediate_dominators[node]
}
/// Provides an iterator over each dominator up the CFG, for the given Node.
/// See the `impl Iterator for Iter` definition to understand how this works.
pub fn dominators(&self, node: Node) -> Iter<'_, Node> {
assert!(self.is_reachable(node), "node {node:?} is not reachable");
- Iter { dominators: self, node: Some(node) }
- }
-
- pub fn dominates(&self, dom: Node, node: Node) -> bool {
- // FIXME -- could be optimized by using post-order-rank
- self.dominators(node).any(|n| n == dom)
+ Iter { dom_tree: self, node: Some(node) }
}
/// Provide deterministic ordering of nodes such that, if any two nodes have a dominator
@@ -344,10 +347,22 @@ impl<Node: Idx> Dominators<Node> {
pub fn rank_partial_cmp(&self, lhs: Node, rhs: Node) -> Option<Ordering> {
self.post_order_rank[rhs].partial_cmp(&self.post_order_rank[lhs])
}
+
+ /// Returns true if `a` dominates `b`.
+ ///
+ /// # Panics
+ ///
+ /// Panics if `b` is unreachable.
+ pub fn dominates(&self, a: Node, b: Node) -> bool {
+ let a = self.time[a];
+ let b = self.time[b];
+ assert!(b.start != 0, "node {b:?} is not reachable");
+ a.start <= b.start && b.finish <= a.finish
+ }
}
pub struct Iter<'dom, Node: Idx> {
- dominators: &'dom Dominators<Node>,
+ dom_tree: &'dom Dominators<Node>,
node: Option<Node>,
}
@@ -356,15 +371,74 @@ impl<'dom, Node: Idx> Iterator for Iter<'dom, Node> {
fn next(&mut self) -> Option<Self::Item> {
if let Some(node) = self.node {
- let dom = self.dominators.immediate_dominator(node);
- if dom == node {
- self.node = None; // reached the root
- } else {
- self.node = Some(dom);
- }
+ self.node = self.dom_tree.immediate_dominator(node);
Some(node)
} else {
None
}
}
}
+
+/// Describes the number of vertices discovered at the time when processing of a particular vertex
+/// started and when it finished. Both values are zero for unreachable vertices.
+#[derive(Copy, Clone, Default, Debug)]
+struct Time {
+ start: u32,
+ finish: u32,
+}
+
+fn compute_access_time<N: Idx>(
+ start_node: N,
+ immediate_dominators: &IndexSlice<N, Option<N>>,
+) -> IndexVec<N, Time> {
+ // Transpose the dominator tree edges, so that child nodes of vertex v are stored in
+ // node[edges[v].start..edges[v].end].
+ let mut edges: IndexVec<N, std::ops::Range<u32>> =
+ IndexVec::from_elem(0..0, immediate_dominators);
+ for &idom in immediate_dominators.iter() {
+ if let Some(idom) = idom {
+ edges[idom].end += 1;
+ }
+ }
+ let mut m = 0;
+ for e in edges.iter_mut() {
+ m += e.end;
+ e.start = m;
+ e.end = m;
+ }
+ let mut node = IndexVec::from_elem_n(Idx::new(0), m.try_into().unwrap());
+ for (i, &idom) in immediate_dominators.iter_enumerated() {
+ if let Some(idom) = idom {
+ edges[idom].start -= 1;
+ node[edges[idom].start] = i;
+ }
+ }
+
+ // Perform a depth-first search of the dominator tree. Record the number of vertices discovered
+ // when vertex v is discovered first as time[v].start, and when its processing is finished as
+ // time[v].finish.
+ let mut time: IndexVec<N, Time> = IndexVec::from_elem(Time::default(), immediate_dominators);
+ let mut stack = Vec::new();
+
+ let mut discovered = 1;
+ stack.push(start_node);
+ time[start_node].start = discovered;
+
+ while let Some(&i) = stack.last() {
+ let e = &mut edges[i];
+ if e.start == e.end {
+ // Finish processing vertex i.
+ time[i].finish = discovered;
+ stack.pop();
+ } else {
+ let j = node[e.start];
+ e.start += 1;
+ // Start processing vertex j.
+ discovered += 1;
+ time[j].start = discovered;
+ stack.push(j);
+ }
+ }
+
+ time
+}
diff --git a/compiler/rustc_data_structures/src/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
index ff31d8f7f..5472bb808 100644
--- a/compiler/rustc_data_structures/src/graph/dominators/tests.rs
+++ b/compiler/rustc_data_structures/src/graph/dominators/tests.rs
@@ -8,7 +8,7 @@ fn diamond() {
let dominators = dominators(&graph);
let immediate_dominators = &dominators.immediate_dominators;
- assert_eq!(immediate_dominators[0], Some(0));
+ assert_eq!(immediate_dominators[0], None);
assert_eq!(immediate_dominators[1], Some(0));
assert_eq!(immediate_dominators[2], Some(0));
assert_eq!(immediate_dominators[3], Some(0));
@@ -30,7 +30,7 @@ fn paper() {
assert_eq!(immediate_dominators[3], Some(6));
assert_eq!(immediate_dominators[4], Some(6));
assert_eq!(immediate_dominators[5], Some(6));
- assert_eq!(immediate_dominators[6], Some(6));
+ assert_eq!(immediate_dominators[6], None);
}
#[test]
@@ -43,3 +43,40 @@ fn paper_slt() {
dominators(&graph);
}
+
+#[test]
+fn immediate_dominator() {
+ let graph = TestGraph::new(1, &[(1, 2), (2, 3)]);
+ let dominators = dominators(&graph);
+ assert_eq!(dominators.immediate_dominator(0), None);
+ assert_eq!(dominators.immediate_dominator(1), None);
+ assert_eq!(dominators.immediate_dominator(2), Some(1));
+ assert_eq!(dominators.immediate_dominator(3), Some(2));
+}
+
+#[test]
+fn transitive_dominator() {
+ let graph = TestGraph::new(
+ 0,
+ &[
+ // First tree branch.
+ (0, 1),
+ (1, 2),
+ (2, 3),
+ (3, 4),
+ // Second tree branch.
+ (1, 5),
+ (5, 6),
+ // Third tree branch.
+ (0, 7),
+ // These links make 0 the dominator for 2 and 3.
+ (7, 2),
+ (5, 3),
+ ],
+ );
+
+ let dom_tree = dominators(&graph);
+ let immediate_dominators = &dom_tree.immediate_dominators;
+ assert_eq!(immediate_dominators[2], Some(0));
+ assert_eq!(immediate_dominators[3], Some(0)); // This used to return Some(1).
+}
diff --git a/compiler/rustc_data_structures/src/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
index 01a83b40a..9eb4b5278 100644
--- a/compiler/rustc_data_structures/src/graph/iterate/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs
@@ -1,6 +1,6 @@
use super::{DirectedGraph, WithNumNodes, WithStartNode, WithSuccessors};
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use std::ops::ControlFlow;
#[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs
index 3560df6e5..e06ab2fe3 100644
--- a/compiler/rustc_data_structures/src/graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/mod.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
pub mod dominators;
pub mod implementation;
diff --git a/compiler/rustc_data_structures/src/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs
index 28c357e54..cf9312ea8 100644
--- a/compiler/rustc_data_structures/src/graph/scc/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/scc/mod.rs
@@ -8,7 +8,7 @@
use crate::fx::FxHashSet;
use crate::graph::vec_graph::VecGraph;
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use std::ops::Range;
#[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
index 94232bb76..00f6266ce 100644
--- a/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
+++ b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs
@@ -1,5 +1,5 @@
use crate::graph::{DirectedGraph, GraphSuccessors, WithNumEdges, WithNumNodes, WithSuccessors};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_data_structures/src/hashes.rs b/compiler/rustc_data_structures/src/hashes.rs
new file mode 100644
index 000000000..ad068cdbc
--- /dev/null
+++ b/compiler/rustc_data_structures/src/hashes.rs
@@ -0,0 +1,132 @@
+//! rustc encodes a lot of hashes. If hashes are stored as `u64` or `u128`, a `derive(Encodable)`
+//! will apply varint encoding to the hashes, which is less efficient than directly encoding the 8
+//! or 16 bytes of the hash.
+//!
+//! The types in this module represent 64-bit or 128-bit hashes produced by a `StableHasher`.
+//! `Hash64` and `Hash128` expose some utilty functions to encourage users to not extract the inner
+//! hash value as an integer type and accidentally apply varint encoding to it.
+//!
+//! In contrast with `Fingerprint`, users of these types cannot and should not attempt to construct
+//! and decompose these types into constitutent pieces. The point of these types is only to
+//! connect the fact that they can only be produced by a `StableHasher` to their
+//! `Encode`/`Decode` impls.
+
+use crate::stable_hasher::{StableHasher, StableHasherResult};
+use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use std::fmt;
+use std::ops::BitXorAssign;
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
+pub struct Hash64 {
+ inner: u64,
+}
+
+impl Hash64 {
+ pub const ZERO: Hash64 = Hash64 { inner: 0 };
+
+ #[inline]
+ pub(crate) fn new(n: u64) -> Self {
+ Self { inner: n }
+ }
+
+ #[inline]
+ pub fn as_u64(self) -> u64 {
+ self.inner
+ }
+}
+
+impl BitXorAssign<u64> for Hash64 {
+ #[inline]
+ fn bitxor_assign(&mut self, rhs: u64) {
+ self.inner ^= rhs;
+ }
+}
+
+impl<S: Encoder> Encodable<S> for Hash64 {
+ #[inline]
+ fn encode(&self, s: &mut S) {
+ s.emit_raw_bytes(&self.inner.to_le_bytes());
+ }
+}
+
+impl<D: Decoder> Decodable<D> for Hash64 {
+ #[inline]
+ fn decode(d: &mut D) -> Self {
+ Self { inner: u64::from_le_bytes(d.read_raw_bytes(8).try_into().unwrap()) }
+ }
+}
+
+impl StableHasherResult for Hash64 {
+ #[inline]
+ fn finish(hasher: StableHasher) -> Self {
+ Self { inner: hasher.finalize().0 }
+ }
+}
+
+impl fmt::Debug for Hash64 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl fmt::LowerHex for Hash64 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::LowerHex::fmt(&self.inner, f)
+ }
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
+pub struct Hash128 {
+ inner: u128,
+}
+
+impl Hash128 {
+ #[inline]
+ pub fn truncate(self) -> Hash64 {
+ Hash64 { inner: self.inner as u64 }
+ }
+
+ #[inline]
+ pub fn wrapping_add(self, other: Self) -> Self {
+ Self { inner: self.inner.wrapping_add(other.inner) }
+ }
+
+ #[inline]
+ pub fn as_u128(self) -> u128 {
+ self.inner
+ }
+}
+
+impl<S: Encoder> Encodable<S> for Hash128 {
+ #[inline]
+ fn encode(&self, s: &mut S) {
+ s.emit_raw_bytes(&self.inner.to_le_bytes());
+ }
+}
+
+impl<D: Decoder> Decodable<D> for Hash128 {
+ #[inline]
+ fn decode(d: &mut D) -> Self {
+ Self { inner: u128::from_le_bytes(d.read_raw_bytes(16).try_into().unwrap()) }
+ }
+}
+
+impl StableHasherResult for Hash128 {
+ #[inline]
+ fn finish(hasher: StableHasher) -> Self {
+ let (_0, _1) = hasher.finalize();
+ Self { inner: u128::from(_0) | (u128::from(_1) << 64) }
+ }
+}
+
+impl fmt::Debug for Hash128 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.inner.fmt(f)
+ }
+}
+
+impl fmt::LowerHex for Hash128 {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::LowerHex::fmt(&self.inner, f)
+ }
+}
diff --git a/compiler/rustc_data_structures/src/lib.rs b/compiler/rustc_data_structures/src/lib.rs
index e373bd184..859e384d8 100644
--- a/compiler/rustc_data_structures/src/lib.rs
+++ b/compiler/rustc_data_structures/src/lib.rs
@@ -26,13 +26,18 @@
#![feature(test)]
#![feature(thread_id_value)]
#![feature(vec_into_raw_parts)]
+#![feature(allocator_api)]
#![feature(get_mut_unchecked)]
#![feature(lint_reasons)]
#![feature(unwrap_infallible)]
+#![feature(strict_provenance)]
+#![feature(ptr_alignment_type)]
+#![feature(macro_metavar_expr)]
#![allow(rustc::default_hash_types)]
#![allow(rustc::potential_query_instability)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
+#![deny(unsafe_op_in_unsafe_fn)]
#[macro_use]
extern crate tracing;
@@ -73,6 +78,7 @@ pub mod sorted_map;
pub mod stable_hasher;
mod atomic_ref;
pub mod fingerprint;
+pub mod marker;
pub mod profiling;
pub mod sharded;
pub mod stack;
@@ -82,7 +88,9 @@ pub mod transitive_relation;
pub mod vec_linked_list;
pub mod work_queue;
pub use atomic_ref::AtomicRef;
+pub mod aligned;
pub mod frozen;
+mod hashes;
pub mod owned_slice;
pub mod sso;
pub mod steal;
@@ -94,21 +102,27 @@ pub mod unord;
pub use ena::undo_log;
pub use ena::unify;
-pub struct OnDrop<F: Fn()>(pub F);
+/// Returns a structure that calls `f` when dropped.
+pub fn defer<F: FnOnce()>(f: F) -> OnDrop<F> {
+ OnDrop(Some(f))
+}
+
+pub struct OnDrop<F: FnOnce()>(Option<F>);
-impl<F: Fn()> OnDrop<F> {
- /// Forgets the function which prevents it from running.
- /// Ensure that the function owns no memory, otherwise it will be leaked.
+impl<F: FnOnce()> OnDrop<F> {
+ /// Disables on-drop call.
#[inline]
- pub fn disable(self) {
- std::mem::forget(self);
+ pub fn disable(mut self) {
+ self.0.take();
}
}
-impl<F: Fn()> Drop for OnDrop<F> {
+impl<F: FnOnce()> Drop for OnDrop<F> {
#[inline]
fn drop(&mut self) {
- (self.0)();
+ if let Some(f) = self.0.take() {
+ f();
+ }
}
}
diff --git a/compiler/rustc_data_structures/src/marker.rs b/compiler/rustc_data_structures/src/marker.rs
new file mode 100644
index 000000000..f8c06f9a8
--- /dev/null
+++ b/compiler/rustc_data_structures/src/marker.rs
@@ -0,0 +1,257 @@
+cfg_if!(
+ if #[cfg(not(parallel_compiler))] {
+ pub auto trait DynSend {}
+ pub auto trait DynSync {}
+
+ impl<T> DynSend for T {}
+ impl<T> DynSync for T {}
+ } else {
+ #[rustc_on_unimplemented(
+ message = "`{Self}` doesn't implement `DynSend`. \
+ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Send`"
+ )]
+ // This is an auto trait for types which can be sent across threads if `sync::is_dyn_thread_safe()`
+ // is true. These types can be wrapped in a `FromDyn` to get a `Send` type. Wrapping a
+ // `Send` type in `IntoDynSyncSend` will create a `DynSend` type.
+ pub unsafe auto trait DynSend {}
+
+ #[rustc_on_unimplemented(
+ message = "`{Self}` doesn't implement `DynSync`. \
+ Add it to `rustc_data_structures::marker` or use `IntoDynSyncSend` if it's already `Sync`"
+ )]
+ // This is an auto trait for types which can be shared across threads if `sync::is_dyn_thread_safe()`
+ // is true. These types can be wrapped in a `FromDyn` to get a `Sync` type. Wrapping a
+ // `Sync` type in `IntoDynSyncSend` will create a `DynSync` type.
+ pub unsafe auto trait DynSync {}
+
+ // Same with `Sync` and `Send`.
+ unsafe impl<T: DynSync + ?Sized> DynSend for &T {}
+
+ macro_rules! impls_dyn_send_neg {
+ ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
+ $(impl$(<$($generics1)*>)? !DynSend for $t1 {})*
+ };
+ }
+
+ // Consistent with `std`
+ impls_dyn_send_neg!(
+ [std::env::Args]
+ [std::env::ArgsOs]
+ [*const T where T: ?Sized]
+ [*mut T where T: ?Sized]
+ [std::ptr::NonNull<T> where T: ?Sized]
+ [std::rc::Rc<T> where T: ?Sized]
+ [std::rc::Weak<T> where T: ?Sized]
+ [std::sync::MutexGuard<'_, T> where T: ?Sized]
+ [std::sync::RwLockReadGuard<'_, T> where T: ?Sized]
+ [std::sync::RwLockWriteGuard<'_, T> where T: ?Sized]
+ [std::io::StdoutLock<'_>]
+ [std::io::StderrLock<'_>]
+ );
+ cfg_if!(
+ // Consistent with `std`
+ // `os_imp::Env` is `!Send` in these platforms
+ if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] {
+ impl !DynSend for std::env::VarsOs {}
+ }
+ );
+
+ macro_rules! already_send {
+ ($([$ty: ty])*) => {
+ $(unsafe impl DynSend for $ty where $ty: Send {})*
+ };
+ }
+
+ // These structures are already `Send`.
+ already_send!(
+ [std::backtrace::Backtrace]
+ [std::io::Stdout]
+ [std::io::Stderr]
+ [std::io::Error]
+ [std::fs::File]
+ [rustc_arena::DroplessArena]
+ [crate::memmap::Mmap]
+ [crate::profiling::SelfProfiler]
+ [crate::owned_slice::OwnedSlice]
+ );
+
+ macro_rules! impl_dyn_send {
+ ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
+ $(unsafe impl<$($generics2)*> DynSend for $ty {})*
+ };
+ }
+
+ impl_dyn_send!(
+ [std::sync::atomic::AtomicPtr<T> where T]
+ [std::sync::Mutex<T> where T: ?Sized+ DynSend]
+ [std::sync::mpsc::Sender<T> where T: DynSend]
+ [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
+ [std::sync::LazyLock<T, F> where T: DynSend, F: DynSend]
+ [std::collections::HashSet<K, S> where K: DynSend, S: DynSend]
+ [std::collections::HashMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
+ [std::collections::BTreeMap<K, V, A> where K: DynSend, V: DynSend, A: std::alloc::Allocator + Clone + DynSend]
+ [Vec<T, A> where T: DynSend, A: std::alloc::Allocator + DynSend]
+ [Box<T, A> where T: ?Sized + DynSend, A: std::alloc::Allocator + DynSend]
+ [crate::sync::Lock<T> where T: DynSend]
+ [crate::sync::RwLock<T> where T: DynSend]
+ [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Send + crate::tagged_ptr::Pointer, T: Send + crate::tagged_ptr::Tag, const CP: bool]
+ [rustc_arena::TypedArena<T> where T: DynSend]
+ [indexmap::IndexSet<V, S> where V: DynSend, S: DynSend]
+ [indexmap::IndexMap<K, V, S> where K: DynSend, V: DynSend, S: DynSend]
+ [thin_vec::ThinVec<T> where T: DynSend]
+ [smallvec::SmallVec<A> where A: smallvec::Array + DynSend]
+ );
+
+ macro_rules! impls_dyn_sync_neg {
+ ($([$t1: ty $(where $($generics1: tt)*)?])*) => {
+ $(impl$(<$($generics1)*>)? !DynSync for $t1 {})*
+ };
+ }
+
+ // Consistent with `std`
+ impls_dyn_sync_neg!(
+ [std::env::Args]
+ [std::env::ArgsOs]
+ [*const T where T: ?Sized]
+ [*mut T where T: ?Sized]
+ [std::cell::Cell<T> where T: ?Sized]
+ [std::cell::RefCell<T> where T: ?Sized]
+ [std::cell::UnsafeCell<T> where T: ?Sized]
+ [std::ptr::NonNull<T> where T: ?Sized]
+ [std::rc::Rc<T> where T: ?Sized]
+ [std::rc::Weak<T> where T: ?Sized]
+ [std::cell::OnceCell<T> where T]
+ [std::sync::mpsc::Receiver<T> where T]
+ [std::sync::mpsc::Sender<T> where T]
+ );
+ cfg_if!(
+ // Consistent with `std`
+ // `os_imp::Env` is `!Sync` in these platforms
+ if #[cfg(any(unix, target_os = "hermit", target_os = "wasi", target_os = "solid_asp3"))] {
+ impl !DynSync for std::env::VarsOs {}
+ }
+ );
+
+ macro_rules! already_sync {
+ ($([$ty: ty])*) => {
+ $(unsafe impl DynSync for $ty where $ty: Sync {})*
+ };
+ }
+
+ // These structures are already `Sync`.
+ already_sync!(
+ [std::sync::atomic::AtomicBool]
+ [std::sync::atomic::AtomicUsize]
+ [std::sync::atomic::AtomicU8]
+ [std::sync::atomic::AtomicU32]
+ [std::sync::atomic::AtomicU64]
+ [std::backtrace::Backtrace]
+ [std::io::Error]
+ [std::fs::File]
+ [jobserver_crate::Client]
+ [crate::memmap::Mmap]
+ [crate::profiling::SelfProfiler]
+ [crate::owned_slice::OwnedSlice]
+ );
+
+ macro_rules! impl_dyn_sync {
+ ($($($attr: meta)* [$ty: ty where $($generics2: tt)*])*) => {
+ $(unsafe impl<$($generics2)*> DynSync for $ty {})*
+ };
+ }
+
+ impl_dyn_sync!(
+ [std::sync::atomic::AtomicPtr<T> where T]
+ [std::sync::OnceLock<T> where T: DynSend + DynSync]
+ [std::sync::Mutex<T> where T: ?Sized + DynSend]
+ [std::sync::Arc<T> where T: ?Sized + DynSync + DynSend]
+ [std::sync::LazyLock<T, F> where T: DynSend + DynSync, F: DynSend]
+ [std::collections::HashSet<K, S> where K: DynSync, S: DynSync]
+ [std::collections::HashMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
+ [std::collections::BTreeMap<K, V, A> where K: DynSync, V: DynSync, A: std::alloc::Allocator + Clone + DynSync]
+ [Vec<T, A> where T: DynSync, A: std::alloc::Allocator + DynSync]
+ [Box<T, A> where T: ?Sized + DynSync, A: std::alloc::Allocator + DynSync]
+ [crate::sync::Lock<T> where T: DynSend]
+ [crate::sync::RwLock<T> where T: DynSend + DynSync]
+ [crate::sync::OneThread<T> where T]
+ [crate::sync::WorkerLocal<T> where T: DynSend]
+ [crate::intern::Interned<'a, T> where 'a, T: DynSync]
+ [crate::tagged_ptr::CopyTaggedPtr<P, T, CP> where P: Sync + crate::tagged_ptr::Pointer, T: Sync + crate::tagged_ptr::Tag, const CP: bool]
+ [parking_lot::lock_api::Mutex<R, T> where R: DynSync, T: ?Sized + DynSend]
+ [parking_lot::lock_api::RwLock<R, T> where R: DynSync, T: ?Sized + DynSend + DynSync]
+ [indexmap::IndexSet<V, S> where V: DynSync, S: DynSync]
+ [indexmap::IndexMap<K, V, S> where K: DynSync, V: DynSync, S: DynSync]
+ [smallvec::SmallVec<A> where A: smallvec::Array + DynSync]
+ [thin_vec::ThinVec<T> where T: DynSync]
+ );
+ }
+);
+
+pub fn assert_dyn_sync<T: ?Sized + DynSync>() {}
+pub fn assert_dyn_send<T: ?Sized + DynSend>() {}
+pub fn assert_dyn_send_val<T: ?Sized + DynSend>(_t: &T) {}
+pub fn assert_dyn_send_sync_val<T: ?Sized + DynSync + DynSend>(_t: &T) {}
+
+#[derive(Copy, Clone)]
+pub struct FromDyn<T>(T);
+
+impl<T> FromDyn<T> {
+ #[inline(always)]
+ pub fn from(val: T) -> Self {
+ // Check that `sync::is_dyn_thread_safe()` is true on creation so we can
+ // implement `Send` and `Sync` for this structure when `T`
+ // implements `DynSend` and `DynSync` respectively.
+ #[cfg(parallel_compiler)]
+ assert!(crate::sync::is_dyn_thread_safe());
+ FromDyn(val)
+ }
+
+ #[inline(always)]
+ pub fn into_inner(self) -> T {
+ self.0
+ }
+}
+
+// `FromDyn` is `Send` if `T` is `DynSend`, since it ensures that sync::is_dyn_thread_safe() is true.
+#[cfg(parallel_compiler)]
+unsafe impl<T: DynSend> Send for FromDyn<T> {}
+
+// `FromDyn` is `Sync` if `T` is `DynSync`, since it ensures that sync::is_dyn_thread_safe() is true.
+#[cfg(parallel_compiler)]
+unsafe impl<T: DynSync> Sync for FromDyn<T> {}
+
+impl<T> std::ops::Deref for FromDyn<T> {
+ type Target = T;
+
+ #[inline(always)]
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+// A wrapper to convert a struct that is already a `Send` or `Sync` into
+// an instance of `DynSend` and `DynSync`, since the compiler cannot infer
+// it automatically in some cases. (e.g. Box<dyn Send / Sync>)
+#[derive(Copy, Clone)]
+pub struct IntoDynSyncSend<T: ?Sized>(pub T);
+
+#[cfg(parallel_compiler)]
+unsafe impl<T: ?Sized + Send> DynSend for IntoDynSyncSend<T> {}
+#[cfg(parallel_compiler)]
+unsafe impl<T: ?Sized + Sync> DynSync for IntoDynSyncSend<T> {}
+
+impl<T> std::ops::Deref for IntoDynSyncSend<T> {
+ type Target = T;
+
+ #[inline(always)]
+ fn deref(&self) -> &T {
+ &self.0
+ }
+}
+
+impl<T> std::ops::DerefMut for IntoDynSyncSend<T> {
+ #[inline(always)]
+ fn deref_mut(&mut self) -> &mut T {
+ &mut self.0
+ }
+}
diff --git a/compiler/rustc_data_structures/src/memmap.rs b/compiler/rustc_data_structures/src/memmap.rs
index ef37a606f..ca908671a 100644
--- a/compiler/rustc_data_structures/src/memmap.rs
+++ b/compiler/rustc_data_structures/src/memmap.rs
@@ -13,7 +13,8 @@ pub struct Mmap(Vec<u8>);
impl Mmap {
#[inline]
pub unsafe fn map(file: File) -> io::Result<Self> {
- memmap2::Mmap::map(&file).map(Mmap)
+ // Safety: this is in fact not safe.
+ unsafe { memmap2::Mmap::map(&file).map(Mmap) }
}
}
diff --git a/compiler/rustc_data_structures/src/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
index 27a869eb7..a47908648 100644
--- a/compiler/rustc_data_structures/src/obligation_forest/mod.rs
+++ b/compiler/rustc_data_structures/src/obligation_forest/mod.rs
@@ -366,7 +366,7 @@ impl<O: ForestObligation> ObligationForest<O> {
&& self
.error_cache
.get(&obligation_tree_id)
- .map_or(false, |errors| errors.contains(v.key()));
+ .is_some_and(|errors| errors.contains(v.key()));
if already_failed {
Err(())
diff --git a/compiler/rustc_data_structures/src/owned_slice.rs b/compiler/rustc_data_structures/src/owned_slice.rs
index 048401f66..cbb3047d8 100644
--- a/compiler/rustc_data_structures/src/owned_slice.rs
+++ b/compiler/rustc_data_structures/src/owned_slice.rs
@@ -1,5 +1,6 @@
use std::{borrow::Borrow, ops::Deref};
+use crate::sync::Lrc;
// Use our fake Send/Sync traits when on not parallel compiler,
// so that `OwnedSlice` only implements/requires Send/Sync
// for parallel compiler builds.
@@ -7,7 +8,7 @@ use crate::sync::{Send, Sync};
/// An owned slice.
///
-/// This is similar to `Box<[u8]>` but allows slicing and using anything as the
+/// This is similar to `Lrc<[u8]>` but allows slicing and using anything as the
/// backing buffer.
///
/// See [`slice_owned`] for `OwnedSlice` construction and examples.
@@ -16,6 +17,7 @@ use crate::sync::{Send, Sync};
///
/// This is essentially a replacement for `owning_ref` which is a lot simpler
/// and even sound! 🌸
+#[derive(Clone)]
pub struct OwnedSlice {
/// This is conceptually a `&'self.owner [u8]`.
bytes: *const [u8],
@@ -31,7 +33,7 @@ pub struct OwnedSlice {
// \/
// ⊂(´・◡・⊂ )∘˚˳° (I am the phantom remnant of #97770)
#[expect(dead_code)]
- owner: Box<dyn Send + Sync>,
+ owner: Lrc<dyn Send + Sync>,
}
/// Makes an [`OwnedSlice`] out of an `owner` and a `slicer` function.
@@ -72,10 +74,10 @@ where
O: Send + Sync + 'static,
F: FnOnce(&O) -> Result<&[u8], E>,
{
- // We box the owner of the bytes, so it doesn't move.
+ // We wrap the owner of the bytes in, so it doesn't move.
//
// Since the owner does not move and we don't access it in any way
- // before drop, there is nothing that can invalidate the bytes pointer.
+ // before dropping, there is nothing that can invalidate the bytes pointer.
//
// Thus, "extending" the lifetime of the reference returned from `F` is fine.
// We pretend that we pass it a reference that lives as long as the returned slice.
@@ -83,12 +85,39 @@ where
// N.B. the HRTB on the `slicer` is important — without it the caller could provide
// a short lived slice, unrelated to the owner.
- let owner = Box::new(owner);
+ let owner = Lrc::new(owner);
let bytes = slicer(&*owner)?;
Ok(OwnedSlice { bytes, owner })
}
+impl OwnedSlice {
+ /// Slice this slice by `slicer`.
+ ///
+ /// # Examples
+ ///
+ /// ```rust
+ /// # use rustc_data_structures::owned_slice::{OwnedSlice, slice_owned};
+ /// let vec = vec![1, 2, 3, 4];
+ ///
+ /// // Identical to slicing via `&v[1..3]` but produces an owned slice
+ /// let slice: OwnedSlice = slice_owned(vec, |v| &v[..]);
+ /// assert_eq!(&*slice, [1, 2, 3, 4]);
+ ///
+ /// let slice = slice.slice(|slice| &slice[1..][..2]);
+ /// assert_eq!(&*slice, [2, 3]);
+ /// ```
+ ///
+ pub fn slice(self, slicer: impl FnOnce(&[u8]) -> &[u8]) -> OwnedSlice {
+ // This is basically identical to `try_slice_owned`,
+ // `slicer` can only return slices of its argument or some static data,
+ // both of which are valid while `owner` is alive.
+
+ let bytes = slicer(&self);
+ OwnedSlice { bytes, ..self }
+ }
+}
+
impl Deref for OwnedSlice {
type Target = [u8];
@@ -108,10 +137,12 @@ impl Borrow<[u8]> for OwnedSlice {
}
}
-// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Send`
+// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Send`
+#[cfg(parallel_compiler)]
unsafe impl Send for OwnedSlice {}
-// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Box<dyn Send + Sync>)`, which is `Sync`
+// Safety: `OwnedSlice` is conceptually `(&'self.1 [u8], Arc<dyn Send + Sync>)`, which is `Sync`
+#[cfg(parallel_compiler)]
unsafe impl Sync for OwnedSlice {}
#[cfg(test)]
diff --git a/compiler/rustc_data_structures/src/owned_slice/tests.rs b/compiler/rustc_data_structures/src/owned_slice/tests.rs
index e715fb553..520871a12 100644
--- a/compiler/rustc_data_structures/src/owned_slice/tests.rs
+++ b/compiler/rustc_data_structures/src/owned_slice/tests.rs
@@ -7,8 +7,8 @@ use std::{
};
use crate::{
+ defer,
owned_slice::{slice_owned, try_slice_owned, OwnedSlice},
- OnDrop,
};
#[test]
@@ -26,7 +26,7 @@ fn static_storage() {
}
#[test]
-fn slice_the_slice() {
+fn slice_owned_the_slice() {
let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice);
let slice = slice_owned(slice, |s| &s[1..][..4]);
let slice = slice_owned(slice, |s| s);
@@ -36,6 +36,16 @@ fn slice_the_slice() {
}
#[test]
+fn slice_the_slice() {
+ let slice = slice_owned(vec![1, 2, 3, 4, 5, 6], Vec::as_slice)
+ .slice(|s| &s[1..][..4])
+ .slice(|s| s)
+ .slice(|s| &s[1..]);
+
+ assert_eq!(&*slice, &[1, 2, 3, 4, 5, 6][1..][..4][1..]);
+}
+
+#[test]
fn try_and_fail() {
let res = try_slice_owned(vec![0], |v| v.get(12..).ok_or(()));
@@ -56,7 +66,7 @@ fn boxed() {
fn drop_drops() {
let flag = Arc::new(AtomicBool::new(false));
let flag_prime = Arc::clone(&flag);
- let d = OnDrop(move || flag_prime.store(true, atomic::Ordering::Relaxed));
+ let d = defer(move || flag_prime.store(true, atomic::Ordering::Relaxed));
let slice = slice_owned(d, |_| &[]);
@@ -69,6 +79,6 @@ fn drop_drops() {
#[test]
fn send_sync() {
- crate::sync::assert_send::<OwnedSlice>();
- crate::sync::assert_sync::<OwnedSlice>();
+ crate::sync::assert_dyn_send::<OwnedSlice>();
+ crate::sync::assert_dyn_sync::<OwnedSlice>();
}
diff --git a/compiler/rustc_data_structures/src/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs
index 1ed584eaf..3c76c2b79 100644
--- a/compiler/rustc_data_structures/src/profiling.rs
+++ b/compiler/rustc_data_structures/src/profiling.rs
@@ -87,6 +87,7 @@ use crate::fx::FxHashMap;
use std::borrow::Borrow;
use std::collections::hash_map::Entry;
use std::error::Error;
+use std::fmt::Display;
use std::fs;
use std::intrinsics::unlikely;
use std::path::Path;
@@ -97,11 +98,10 @@ use std::time::{Duration, Instant};
pub use measureme::EventId;
use measureme::{EventIdBuilder, Profiler, SerializableString, StringId};
use parking_lot::RwLock;
-use serde_json::json;
use smallvec::SmallVec;
bitflags::bitflags! {
- struct EventFilter: u32 {
+ struct EventFilter: u16 {
const GENERIC_ACTIVITIES = 1 << 0;
const QUERY_PROVIDERS = 1 << 1;
const QUERY_CACHE_HITS = 1 << 2;
@@ -557,7 +557,7 @@ impl SelfProfiler {
let crate_name = crate_name.unwrap_or("unknown-crate");
// HACK(eddyb) we need to pad the PID, strange as it may seem, as its
// length can behave as a source of entropy for heap addresses, when
- // ASLR is disabled and the heap is otherwise determinic.
+ // ASLR is disabled and the heap is otherwise deterministic.
let pid: u32 = process::id();
let filename = format!("{crate_name}-{pid:07}.rustc_profile");
let path = output_directory.join(&filename);
@@ -763,6 +763,31 @@ impl Drop for VerboseTimingGuard<'_> {
}
}
+struct JsonTimePassesEntry<'a> {
+ pass: &'a str,
+ time: f64,
+ start_rss: Option<usize>,
+ end_rss: Option<usize>,
+}
+
+impl Display for JsonTimePassesEntry<'_> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ let Self { pass: what, time, start_rss, end_rss } = self;
+ write!(f, r#"{{"pass":"{what}","time":{time},"rss_start":"#).unwrap();
+ match start_rss {
+ Some(rss) => write!(f, "{rss}")?,
+ None => write!(f, "null")?,
+ }
+ write!(f, r#","rss_end":"#)?;
+ match end_rss {
+ Some(rss) => write!(f, "{rss}")?,
+ None => write!(f, "null")?,
+ }
+ write!(f, "}}")?;
+ Ok(())
+ }
+}
+
pub fn print_time_passes_entry(
what: &str,
dur: Duration,
@@ -772,13 +797,10 @@ pub fn print_time_passes_entry(
) {
match format {
TimePassesFormat::Json => {
- let json = json!({
- "pass": what,
- "time": dur.as_secs_f64(),
- "rss_start": start_rss,
- "rss_end": end_rss,
- });
- eprintln!("time: {json}");
+ let entry =
+ JsonTimePassesEntry { pass: what, time: dur.as_secs_f64(), start_rss, end_rss };
+
+ eprintln!(r#"time: {entry}"#);
return;
}
TimePassesFormat::Text => (),
@@ -843,14 +865,16 @@ cfg_if! {
use std::mem;
use windows::{
- Win32::System::ProcessStatus::{K32GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
+ // FIXME: change back to K32GetProcessMemoryInfo when windows crate
+ // updated to 0.49.0+ to drop dependency on psapi.dll
+ Win32::System::ProcessStatus::{GetProcessMemoryInfo, PROCESS_MEMORY_COUNTERS},
Win32::System::Threading::GetCurrentProcess,
};
let mut pmc = PROCESS_MEMORY_COUNTERS::default();
let pmc_size = mem::size_of_val(&pmc);
unsafe {
- K32GetProcessMemoryInfo(
+ GetProcessMemoryInfo(
GetCurrentProcess(),
&mut pmc,
pmc_size as u32,
@@ -894,3 +918,6 @@ cfg_if! {
}
}
}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/profiling/tests.rs b/compiler/rustc_data_structures/src/profiling/tests.rs
new file mode 100644
index 000000000..2b09de085
--- /dev/null
+++ b/compiler/rustc_data_structures/src/profiling/tests.rs
@@ -0,0 +1,19 @@
+use super::JsonTimePassesEntry;
+
+#[test]
+fn with_rss() {
+ let entry =
+ JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: Some(10), end_rss: Some(20) };
+
+ assert_eq!(entry.to_string(), r#"{"pass":"typeck","time":56.1,"rss_start":10,"rss_end":20}"#)
+}
+
+#[test]
+fn no_rss() {
+ let entry = JsonTimePassesEntry { pass: "typeck", time: 56.1, start_rss: None, end_rss: None };
+
+ assert_eq!(
+ entry.to_string(),
+ r#"{"pass":"typeck","time":56.1,"rss_start":null,"rss_end":null}"#
+ )
+}
diff --git a/compiler/rustc_data_structures/src/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs
index bd7a86f67..7ed70ba1e 100644
--- a/compiler/rustc_data_structures/src/sharded.rs
+++ b/compiler/rustc_data_structures/src/sharded.rs
@@ -1,14 +1,10 @@
use crate::fx::{FxHashMap, FxHasher};
-use crate::sync::{Lock, LockGuard};
+use crate::sync::{CacheAligned, Lock, LockGuard};
use std::borrow::Borrow;
use std::collections::hash_map::RawEntryMut;
use std::hash::{Hash, Hasher};
use std::mem;
-#[derive(Default)]
-#[cfg_attr(parallel_compiler, repr(align(64)))]
-struct CacheAligned<T>(T);
-
#[cfg(parallel_compiler)]
// 32 shards is sufficient to reduce contention on an 8-core Ryzen 7 1700,
// but this should be tested on higher core count CPUs. How the `Sharded` type gets used
diff --git a/compiler/rustc_data_structures/src/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs
index d849fe037..4a0ed87f7 100644
--- a/compiler/rustc_data_structures/src/sip128.rs
+++ b/compiler/rustc_data_structures/src/sip128.rs
@@ -96,28 +96,30 @@ macro_rules! compress {
unsafe fn copy_nonoverlapping_small(src: *const u8, dst: *mut u8, count: usize) {
debug_assert!(count <= 8);
- if count == 8 {
- ptr::copy_nonoverlapping(src, dst, 8);
- return;
- }
+ unsafe {
+ if count == 8 {
+ ptr::copy_nonoverlapping(src, dst, 8);
+ return;
+ }
- let mut i = 0;
- if i + 3 < count {
- ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4);
- i += 4;
- }
+ let mut i = 0;
+ if i + 3 < count {
+ ptr::copy_nonoverlapping(src.add(i), dst.add(i), 4);
+ i += 4;
+ }
- if i + 1 < count {
- ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2);
- i += 2
- }
+ if i + 1 < count {
+ ptr::copy_nonoverlapping(src.add(i), dst.add(i), 2);
+ i += 2
+ }
- if i < count {
- *dst.add(i) = *src.add(i);
- i += 1;
- }
+ if i < count {
+ *dst.add(i) = *src.add(i);
+ i += 1;
+ }
- debug_assert_eq!(i, count);
+ debug_assert_eq!(i, count);
+ }
}
// # Implementation
@@ -232,38 +234,40 @@ impl SipHasher128 {
// overflow) if it wasn't already.
#[inline(never)]
unsafe fn short_write_process_buffer<const LEN: usize>(&mut self, bytes: [u8; LEN]) {
- let nbuf = self.nbuf;
- debug_assert!(LEN <= 8);
- debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + LEN >= BUFFER_SIZE);
- debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
+ unsafe {
+ let nbuf = self.nbuf;
+ debug_assert!(LEN <= 8);
+ debug_assert!(nbuf < BUFFER_SIZE);
+ debug_assert!(nbuf + LEN >= BUFFER_SIZE);
+ debug_assert!(nbuf + LEN < BUFFER_WITH_SPILL_SIZE);
+
+ // Copy first part of input into end of buffer, possibly into spill
+ // element. The memcpy call is optimized away because the size is known.
+ let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
+ ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
+
+ // Process buffer.
+ for i in 0..BUFFER_CAPACITY {
+ let elem = self.buf.get_unchecked(i).assume_init().to_le();
+ self.state.v3 ^= elem;
+ Sip13Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= elem;
+ }
- // Copy first part of input into end of buffer, possibly into spill
- // element. The memcpy call is optimized away because the size is known.
- let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- ptr::copy_nonoverlapping(bytes.as_ptr(), dst, LEN);
-
- // Process buffer.
- for i in 0..BUFFER_CAPACITY {
- let elem = self.buf.get_unchecked(i).assume_init().to_le();
- self.state.v3 ^= elem;
- Sip13Rounds::c_rounds(&mut self.state);
- self.state.v0 ^= elem;
+ // Copy remaining input into start of buffer by copying LEN - 1
+ // elements from spill (at most LEN - 1 bytes could have overflowed
+ // into the spill). The memcpy call is optimized away because the size
+ // is known. And the whole copy is optimized away for LEN == 1.
+ let dst = self.buf.as_mut_ptr() as *mut u8;
+ let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
+ ptr::copy_nonoverlapping(src, dst, LEN - 1);
+
+ // This function should only be called when the write fills the buffer.
+ // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
+ // LEN is statically known, so the branch is optimized away.
+ self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
+ self.processed += BUFFER_SIZE;
}
-
- // Copy remaining input into start of buffer by copying LEN - 1
- // elements from spill (at most LEN - 1 bytes could have overflowed
- // into the spill). The memcpy call is optimized away because the size
- // is known. And the whole copy is optimized away for LEN == 1.
- let dst = self.buf.as_mut_ptr() as *mut u8;
- let src = self.buf.get_unchecked(BUFFER_SPILL_INDEX) as *const _ as *const u8;
- ptr::copy_nonoverlapping(src, dst, LEN - 1);
-
- // This function should only be called when the write fills the buffer.
- // Therefore, when LEN == 1, the new `self.nbuf` must be zero.
- // LEN is statically known, so the branch is optimized away.
- self.nbuf = if LEN == 1 { 0 } else { nbuf + LEN - BUFFER_SIZE };
- self.processed += BUFFER_SIZE;
}
// A write function for byte slices.
@@ -301,57 +305,59 @@ impl SipHasher128 {
// containing the byte offset `self.nbuf`.
#[inline(never)]
unsafe fn slice_write_process_buffer(&mut self, msg: &[u8]) {
- let length = msg.len();
- let nbuf = self.nbuf;
- debug_assert!(nbuf < BUFFER_SIZE);
- debug_assert!(nbuf + length >= BUFFER_SIZE);
-
- // Always copy first part of input into current element of buffer.
- // This function should only be called when the write fills the buffer,
- // so we know that there is enough input to fill the current element.
- let valid_in_elem = nbuf % ELEM_SIZE;
- let needed_in_elem = ELEM_SIZE - valid_in_elem;
-
- let src = msg.as_ptr();
- let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
- copy_nonoverlapping_small(src, dst, needed_in_elem);
-
- // Process buffer.
+ unsafe {
+ let length = msg.len();
+ let nbuf = self.nbuf;
+ debug_assert!(nbuf < BUFFER_SIZE);
+ debug_assert!(nbuf + length >= BUFFER_SIZE);
+
+ // Always copy first part of input into current element of buffer.
+ // This function should only be called when the write fills the buffer,
+ // so we know that there is enough input to fill the current element.
+ let valid_in_elem = nbuf % ELEM_SIZE;
+ let needed_in_elem = ELEM_SIZE - valid_in_elem;
+
+ let src = msg.as_ptr();
+ let dst = (self.buf.as_mut_ptr() as *mut u8).add(nbuf);
+ copy_nonoverlapping_small(src, dst, needed_in_elem);
+
+ // Process buffer.
+
+ // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) /
+ // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0.
+ // We know that is true, because last step ensured we have a full
+ // element in the buffer.
+ let last = nbuf / ELEM_SIZE + 1;
+
+ for i in 0..last {
+ let elem = self.buf.get_unchecked(i).assume_init().to_le();
+ self.state.v3 ^= elem;
+ Sip13Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= elem;
+ }
- // Using `nbuf / ELEM_SIZE + 1` rather than `(nbuf + needed_in_elem) /
- // ELEM_SIZE` to show the compiler that this loop's upper bound is > 0.
- // We know that is true, because last step ensured we have a full
- // element in the buffer.
- let last = nbuf / ELEM_SIZE + 1;
+ // Process the remaining element-sized chunks of input.
+ let mut processed = needed_in_elem;
+ let input_left = length - processed;
+ let elems_left = input_left / ELEM_SIZE;
+ let extra_bytes_left = input_left % ELEM_SIZE;
+
+ for _ in 0..elems_left {
+ let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le();
+ self.state.v3 ^= elem;
+ Sip13Rounds::c_rounds(&mut self.state);
+ self.state.v0 ^= elem;
+ processed += ELEM_SIZE;
+ }
- for i in 0..last {
- let elem = self.buf.get_unchecked(i).assume_init().to_le();
- self.state.v3 ^= elem;
- Sip13Rounds::c_rounds(&mut self.state);
- self.state.v0 ^= elem;
- }
+ // Copy remaining input into start of buffer.
+ let src = msg.as_ptr().add(processed);
+ let dst = self.buf.as_mut_ptr() as *mut u8;
+ copy_nonoverlapping_small(src, dst, extra_bytes_left);
- // Process the remaining element-sized chunks of input.
- let mut processed = needed_in_elem;
- let input_left = length - processed;
- let elems_left = input_left / ELEM_SIZE;
- let extra_bytes_left = input_left % ELEM_SIZE;
-
- for _ in 0..elems_left {
- let elem = (msg.as_ptr().add(processed) as *const u64).read_unaligned().to_le();
- self.state.v3 ^= elem;
- Sip13Rounds::c_rounds(&mut self.state);
- self.state.v0 ^= elem;
- processed += ELEM_SIZE;
+ self.nbuf = extra_bytes_left;
+ self.processed += nbuf + processed;
}
-
- // Copy remaining input into start of buffer.
- let src = msg.as_ptr().add(processed);
- let dst = self.buf.as_mut_ptr() as *mut u8;
- copy_nonoverlapping_small(src, dst, extra_bytes_left);
-
- self.nbuf = extra_bytes_left;
- self.processed += nbuf + processed;
}
#[inline]
diff --git a/compiler/rustc_data_structures/src/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
index 7d23ff519..c172ee1c9 100644
--- a/compiler/rustc_data_structures/src/sorted_map/index_map.rs
+++ b/compiler/rustc_data_structures/src/sorted_map/index_map.rs
@@ -3,7 +3,7 @@
use std::hash::{Hash, Hasher};
use crate::stable_hasher::{HashStable, StableHasher};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
/// An indexed multi-map that preserves insertion order while permitting both *O*(log *n*) lookup of
/// an item by key and *O*(1) lookup by index.
diff --git a/compiler/rustc_data_structures/src/sso/map.rs b/compiler/rustc_data_structures/src/sso/map.rs
index 89b8c8526..99581ed23 100644
--- a/compiler/rustc_data_structures/src/sso/map.rs
+++ b/compiler/rustc_data_structures/src/sso/map.rs
@@ -256,12 +256,9 @@ impl<K: Eq + Hash, V> SsoHashMap<K, V> {
pub fn remove(&mut self, key: &K) -> Option<V> {
match self {
SsoHashMap::Array(array) => {
- if let Some(index) = array.iter().position(|(k, _v)| k == key) {
- Some(array.swap_remove(index).1)
- } else {
- None
- }
+ array.iter().position(|(k, _v)| k == key).map(|index| array.swap_remove(index).1)
}
+
SsoHashMap::Map(map) => map.remove(key),
}
}
diff --git a/compiler/rustc_data_structures/src/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs
index 3ed1de1bc..6d57d81c5 100644
--- a/compiler/rustc_data_structures/src/stable_hasher.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher.rs
@@ -1,7 +1,8 @@
use crate::sip128::SipHasher128;
-use rustc_index::bit_set;
-use rustc_index::vec;
+use rustc_index::bit_set::{self, BitSet};
+use rustc_index::{Idx, IndexVec};
use smallvec::SmallVec;
+use std::fmt;
use std::hash::{BuildHasher, Hash, Hasher};
use std::marker::PhantomData;
use std::mem;
@@ -9,6 +10,8 @@ use std::mem;
#[cfg(test)]
mod tests;
+pub use crate::hashes::{Hash128, Hash64};
+
/// When hashing something that ends up affecting properties like symbol names,
/// we want these symbol names to be calculated independently of other factors
/// like what architecture you're compiling *from*.
@@ -20,8 +23,8 @@ pub struct StableHasher {
state: SipHasher128,
}
-impl ::std::fmt::Debug for StableHasher {
- fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+impl fmt::Debug for StableHasher {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{:?}", self.state)
}
}
@@ -42,21 +45,6 @@ impl StableHasher {
}
}
-impl StableHasherResult for u128 {
- #[inline]
- fn finish(hasher: StableHasher) -> Self {
- let (_0, _1) = hasher.finalize();
- u128::from(_0) | (u128::from(_1) << 64)
- }
-}
-
-impl StableHasherResult for u64 {
- #[inline]
- fn finish(hasher: StableHasher) -> Self {
- hasher.finalize().0
- }
-}
-
impl StableHasher {
#[inline]
pub fn finalize(self) -> (u64, u64) {
@@ -107,7 +95,8 @@ impl Hasher for StableHasher {
#[inline]
fn write_u128(&mut self, i: u128) {
- self.state.write(&i.to_le_bytes());
+ self.write_u64(i as u64);
+ self.write_u64((i >> 64) as u64);
}
#[inline]
@@ -286,6 +275,9 @@ impl_stable_traits_for_trivial_type!(i128);
impl_stable_traits_for_trivial_type!(char);
impl_stable_traits_for_trivial_type!(());
+impl_stable_traits_for_trivial_type!(Hash64);
+impl_stable_traits_for_trivial_type!(Hash128);
+
impl<CTX> HashStable<CTX> for ! {
fn hash_stable(&self, _ctx: &mut CTX, _hasher: &mut StableHasher) {
unreachable!()
@@ -565,7 +557,7 @@ where
}
}
-impl<I: vec::Idx, T, CTX> HashStable<CTX> for vec::IndexVec<I, T>
+impl<I: Idx, T, CTX> HashStable<CTX> for IndexVec<I, T>
where
T: HashStable<CTX>,
{
@@ -577,13 +569,13 @@ where
}
}
-impl<I: vec::Idx, CTX> HashStable<CTX> for bit_set::BitSet<I> {
+impl<I: Idx, CTX> HashStable<CTX> for BitSet<I> {
fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) {
::std::hash::Hash::hash(self, hasher);
}
}
-impl<R: vec::Idx, C: vec::Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C> {
+impl<R: Idx, C: Idx, CTX> HashStable<CTX> for bit_set::BitMatrix<R, C> {
fn hash_stable(&self, _ctx: &mut CTX, hasher: &mut StableHasher) {
::std::hash::Hash::hash(self, hasher);
}
@@ -668,7 +660,7 @@ fn stable_hash_reduce<HCX, I, C, F>(
.map(|value| {
let mut hasher = StableHasher::new();
hash_function(&mut hasher, hcx, value);
- hasher.finish::<u128>()
+ hasher.finish::<Hash128>()
})
.reduce(|accum, value| accum.wrapping_add(value));
hash.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
index a98b1bc36..c8921f6a7 100644
--- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs
+++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs
@@ -72,7 +72,7 @@ fn test_hash_isize() {
assert_eq!(h.finalize(), expected);
}
-fn hash<T: HashStable<()>>(t: &T) -> u128 {
+fn hash<T: HashStable<()>>(t: &T) -> Hash128 {
let mut h = StableHasher::new();
let ctx = &mut ();
t.hash_stable(ctx, &mut h);
diff --git a/compiler/rustc_data_structures/src/svh.rs b/compiler/rustc_data_structures/src/svh.rs
index 61654b9e8..71679086f 100644
--- a/compiler/rustc_data_structures/src/svh.rs
+++ b/compiler/rustc_data_structures/src/svh.rs
@@ -5,58 +5,36 @@
//! mismatches where we have two versions of the same crate that were
//! compiled from distinct sources.
-use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
+use crate::fingerprint::Fingerprint;
use std::fmt;
-use std::hash::{Hash, Hasher};
use crate::stable_hasher;
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, Hash)]
pub struct Svh {
- hash: u64,
+ hash: Fingerprint,
}
impl Svh {
/// Creates a new `Svh` given the hash. If you actually want to
/// compute the SVH from some HIR, you want the `calculate_svh`
/// function found in `rustc_incremental`.
- pub fn new(hash: u64) -> Svh {
+ pub fn new(hash: Fingerprint) -> Svh {
Svh { hash }
}
- pub fn as_u64(&self) -> u64 {
- self.hash
+ pub fn as_u128(self) -> u128 {
+ self.hash.as_u128()
}
- pub fn to_string(&self) -> String {
- format!("{:016x}", self.hash)
- }
-}
-
-impl Hash for Svh {
- fn hash<H>(&self, state: &mut H)
- where
- H: Hasher,
- {
- self.hash.to_le().hash(state);
+ pub fn to_hex(self) -> String {
+ format!("{:032x}", self.hash.as_u128())
}
}
impl fmt::Display for Svh {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.pad(&self.to_string())
- }
-}
-
-impl<S: Encoder> Encodable<S> for Svh {
- fn encode(&self, s: &mut S) {
- s.emit_u64(self.as_u64().to_le());
- }
-}
-
-impl<D: Decoder> Decodable<D> for Svh {
- fn decode(d: &mut D) -> Svh {
- Svh::new(u64::from_le(d.read_u64()))
+ f.pad(&self.to_hex())
}
}
diff --git a/compiler/rustc_data_structures/src/sync.rs b/compiler/rustc_data_structures/src/sync.rs
index ef1da8519..6c3197d8e 100644
--- a/compiler/rustc_data_structures/src/sync.rs
+++ b/compiler/rustc_data_structures/src/sync.rs
@@ -39,12 +39,15 @@
//!
//! [^2] `MTLockRef` is a typedef.
-use crate::owned_slice::OwnedSlice;
+pub use crate::marker::*;
use std::collections::HashMap;
use std::hash::{BuildHasher, Hash};
use std::ops::{Deref, DerefMut};
use std::panic::{catch_unwind, resume_unwind, AssertUnwindSafe};
+mod worker_local;
+pub use worker_local::{Registry, WorkerLocal};
+
pub use std::sync::atomic::Ordering;
pub use std::sync::atomic::Ordering::SeqCst;
@@ -52,6 +55,43 @@ pub use vec::{AppendOnlyIndexVec, AppendOnlyVec};
mod vec;
+mod mode {
+ use super::Ordering;
+ use std::sync::atomic::AtomicU8;
+
+ const UNINITIALIZED: u8 = 0;
+ const DYN_NOT_THREAD_SAFE: u8 = 1;
+ const DYN_THREAD_SAFE: u8 = 2;
+
+ static DYN_THREAD_SAFE_MODE: AtomicU8 = AtomicU8::new(UNINITIALIZED);
+
+ // Whether thread safety is enabled (due to running under multiple threads).
+ #[inline]
+ pub fn is_dyn_thread_safe() -> bool {
+ match DYN_THREAD_SAFE_MODE.load(Ordering::Relaxed) {
+ DYN_NOT_THREAD_SAFE => false,
+ DYN_THREAD_SAFE => true,
+ _ => panic!("uninitialized dyn_thread_safe mode!"),
+ }
+ }
+
+ // Only set by the `-Z threads` compile option
+ pub fn set_dyn_thread_safe_mode(mode: bool) {
+ let set: u8 = if mode { DYN_THREAD_SAFE } else { DYN_NOT_THREAD_SAFE };
+ let previous = DYN_THREAD_SAFE_MODE.compare_exchange(
+ UNINITIALIZED,
+ set,
+ Ordering::Relaxed,
+ Ordering::Relaxed,
+ );
+
+ // Check that the mode was either uninitialized or was already set to the requested mode.
+ assert!(previous.is_ok() || previous == Err(set));
+ }
+}
+
+pub use mode::{is_dyn_thread_safe, set_dyn_thread_safe_mode};
+
cfg_if! {
if #[cfg(not(parallel_compiler))] {
pub unsafe auto trait Send {}
@@ -146,7 +186,7 @@ cfg_if! {
#[macro_export]
macro_rules! parallel {
- ($($blocks:tt),*) => {
+ ($($blocks:block),*) => {
// We catch panics here ensuring that all the blocks execute.
// This makes behavior consistent with the parallel compiler.
let mut panic = None;
@@ -165,12 +205,6 @@ cfg_if! {
}
}
- pub use Iterator as ParallelIterator;
-
- pub fn par_iter<T: IntoIterator>(t: T) -> T::IntoIter {
- t.into_iter()
- }
-
pub fn par_for_each_in<T: IntoIterator>(t: T, mut for_each: impl FnMut(T::Item) + Sync + Send) {
// We catch panics here ensuring that all the loop iterations execute.
// This makes behavior consistent with the parallel compiler.
@@ -187,7 +221,28 @@ cfg_if! {
}
}
- pub type MetadataRef = OwnedSlice;
+ pub fn par_map<T: IntoIterator, R, C: FromIterator<R>>(
+ t: T,
+ mut map: impl FnMut(<<T as IntoIterator>::IntoIter as Iterator>::Item) -> R,
+ ) -> C {
+ // We catch panics here ensuring that all the loop iterations execute.
+ let mut panic = None;
+ let r = t.into_iter().filter_map(|i| {
+ match catch_unwind(AssertUnwindSafe(|| map(i))) {
+ Ok(r) => Some(r),
+ Err(p) => {
+ if panic.is_none() {
+ panic = Some(p);
+ }
+ None
+ }
+ }
+ }).collect();
+ if let Some(panic) = panic {
+ resume_unwind(panic);
+ }
+ r
+ }
pub use std::rc::Rc as Lrc;
pub use std::rc::Weak as Weak;
@@ -205,33 +260,6 @@ cfg_if! {
use std::cell::Cell;
- #[derive(Debug)]
- pub struct WorkerLocal<T>(OneThread<T>);
-
- impl<T> WorkerLocal<T> {
- /// Creates a new worker local where the `initial` closure computes the
- /// value this worker local should take for each thread in the thread pool.
- #[inline]
- pub fn new<F: FnMut(usize) -> T>(mut f: F) -> WorkerLocal<T> {
- WorkerLocal(OneThread::new(f(0)))
- }
-
- /// Returns the worker-local value for each thread
- #[inline]
- pub fn into_inner(self) -> Vec<T> {
- vec![OneThread::into_inner(self.0)]
- }
- }
-
- impl<T> Deref for WorkerLocal<T> {
- type Target = T;
-
- #[inline(always)]
- fn deref(&self) -> &T {
- &self.0
- }
- }
-
pub type MTLockRef<'a, T> = &'a mut MTLock<T>;
#[derive(Debug, Default)]
@@ -326,51 +354,166 @@ cfg_if! {
use parking_lot::RwLock as InnerRwLock;
use std::thread;
- pub use rayon::{join, scope};
+
+ #[inline]
+ pub fn join<A, B, RA: DynSend, RB: DynSend>(oper_a: A, oper_b: B) -> (RA, RB)
+ where
+ A: FnOnce() -> RA + DynSend,
+ B: FnOnce() -> RB + DynSend,
+ {
+ if mode::is_dyn_thread_safe() {
+ let oper_a = FromDyn::from(oper_a);
+ let oper_b = FromDyn::from(oper_b);
+ let (a, b) = rayon::join(move || FromDyn::from(oper_a.into_inner()()), move || FromDyn::from(oper_b.into_inner()()));
+ (a.into_inner(), b.into_inner())
+ } else {
+ (oper_a(), oper_b())
+ }
+ }
+
+ // This function only works when `mode::is_dyn_thread_safe()`.
+ pub fn scope<'scope, OP, R>(op: OP) -> R
+ where
+ OP: FnOnce(&rayon::Scope<'scope>) -> R + DynSend,
+ R: DynSend,
+ {
+ let op = FromDyn::from(op);
+ rayon::scope(|s| FromDyn::from(op.into_inner()(s))).into_inner()
+ }
/// Runs a list of blocks in parallel. The first block is executed immediately on
/// the current thread. Use that for the longest running block.
#[macro_export]
macro_rules! parallel {
- (impl $fblock:tt [$($c:tt,)*] [$block:tt $(, $rest:tt)*]) => {
+ (impl $fblock:block [$($c:expr,)*] [$block:expr $(, $rest:expr)*]) => {
parallel!(impl $fblock [$block, $($c,)*] [$($rest),*])
};
- (impl $fblock:tt [$($blocks:tt,)*] []) => {
+ (impl $fblock:block [$($blocks:expr,)*] []) => {
::rustc_data_structures::sync::scope(|s| {
+ $(let block = rustc_data_structures::sync::FromDyn::from(|| $blocks);
+ s.spawn(move |_| block.into_inner()());)*
+ (|| $fblock)();
+ });
+ };
+ ($fblock:block, $($blocks:block),*) => {
+ if rustc_data_structures::sync::is_dyn_thread_safe() {
+ // Reverse the order of the later blocks since Rayon executes them in reverse order
+ // when using a single thread. This ensures the execution order matches that
+ // of a single threaded rustc.
+ parallel!(impl $fblock [] [$($blocks),*]);
+ } else {
+ // We catch panics here ensuring that all the blocks execute.
+ // This makes behavior consistent with the parallel compiler.
+ let mut panic = None;
+ if let Err(p) = ::std::panic::catch_unwind(
+ ::std::panic::AssertUnwindSafe(|| $fblock)
+ ) {
+ if panic.is_none() {
+ panic = Some(p);
+ }
+ }
$(
- s.spawn(|_| $blocks);
+ if let Err(p) = ::std::panic::catch_unwind(
+ ::std::panic::AssertUnwindSafe(|| $blocks)
+ ) {
+ if panic.is_none() {
+ panic = Some(p);
+ }
+ }
)*
- $fblock;
- })
- };
- ($fblock:tt, $($blocks:tt),*) => {
- // Reverse the order of the later blocks since Rayon executes them in reverse order
- // when using a single thread. This ensures the execution order matches that
- // of a single threaded rustc
- parallel!(impl $fblock [] [$($blocks),*]);
+ if let Some(panic) = panic {
+ ::std::panic::resume_unwind(panic);
+ }
+ }
};
}
- pub use rayon_core::WorkerLocal;
+ use rayon::iter::{FromParallelIterator, IntoParallelIterator, ParallelIterator};
- pub use rayon::iter::ParallelIterator;
- use rayon::iter::IntoParallelIterator;
+ pub fn par_for_each_in<I, T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>>(
+ t: T,
+ for_each: impl Fn(I) + DynSync + DynSend
+ ) {
+ if mode::is_dyn_thread_safe() {
+ let for_each = FromDyn::from(for_each);
+ let panic: Lock<Option<_>> = Lock::new(None);
+ t.into_par_iter().for_each(|i| if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
+ let mut l = panic.lock();
+ if l.is_none() {
+ *l = Some(p)
+ }
+ });
- pub fn par_iter<T: IntoParallelIterator>(t: T) -> T::Iter {
- t.into_par_iter()
+ if let Some(panic) = panic.into_inner() {
+ resume_unwind(panic);
+ }
+ } else {
+ // We catch panics here ensuring that all the loop iterations execute.
+ // This makes behavior consistent with the parallel compiler.
+ let mut panic = None;
+ t.into_iter().for_each(|i| {
+ if let Err(p) = catch_unwind(AssertUnwindSafe(|| for_each(i))) {
+ if panic.is_none() {
+ panic = Some(p);
+ }
+ }
+ });
+ if let Some(panic) = panic {
+ resume_unwind(panic);
+ }
+ }
}
- pub fn par_for_each_in<T: IntoParallelIterator>(
+ pub fn par_map<
+ I,
+ T: IntoIterator<Item = I> + IntoParallelIterator<Item = I>,
+ R: std::marker::Send,
+ C: FromIterator<R> + FromParallelIterator<R>
+ >(
t: T,
- for_each: impl Fn(T::Item) + Sync + Send,
- ) {
- let ps: Vec<_> = t.into_par_iter().map(|i| catch_unwind(AssertUnwindSafe(|| for_each(i)))).collect();
- ps.into_iter().for_each(|p| if let Err(panic) = p {
- resume_unwind(panic)
- });
- }
+ map: impl Fn(I) -> R + DynSync + DynSend
+ ) -> C {
+ if mode::is_dyn_thread_safe() {
+ let panic: Lock<Option<_>> = Lock::new(None);
+ let map = FromDyn::from(map);
+ // We catch panics here ensuring that all the loop iterations execute.
+ let r = t.into_par_iter().filter_map(|i| {
+ match catch_unwind(AssertUnwindSafe(|| map(i))) {
+ Ok(r) => Some(r),
+ Err(p) => {
+ let mut l = panic.lock();
+ if l.is_none() {
+ *l = Some(p);
+ }
+ None
+ },
+ }
+ }).collect();
- pub type MetadataRef = OwnedSlice;
+ if let Some(panic) = panic.into_inner() {
+ resume_unwind(panic);
+ }
+ r
+ } else {
+ // We catch panics here ensuring that all the loop iterations execute.
+ let mut panic = None;
+ let r = t.into_iter().filter_map(|i| {
+ match catch_unwind(AssertUnwindSafe(|| map(i))) {
+ Ok(r) => Some(r),
+ Err(p) => {
+ if panic.is_none() {
+ panic = Some(p);
+ }
+ None
+ }
+ }
+ }).collect();
+ if let Some(panic) = panic {
+ resume_unwind(panic);
+ }
+ r
+ }
+ }
/// This makes locks panic if they are already held.
/// It is only useful when you are running in a single thread
@@ -378,10 +521,9 @@ cfg_if! {
}
}
-pub fn assert_sync<T: ?Sized + Sync>() {}
-pub fn assert_send<T: ?Sized + Send>() {}
-pub fn assert_send_val<T: ?Sized + Send>(_t: &T) {}
-pub fn assert_send_sync_val<T: ?Sized + Sync + Send>(_t: &T) {}
+#[derive(Default)]
+#[cfg_attr(parallel_compiler, repr(align(64)))]
+pub struct CacheAligned<T>(pub T);
pub trait HashMapExt<K, V> {
/// Same as HashMap::insert, but it may panic if there's already an
diff --git a/compiler/rustc_data_structures/src/sync/vec.rs b/compiler/rustc_data_structures/src/sync/vec.rs
index 1783b4b35..e36dded9e 100644
--- a/compiler/rustc_data_structures/src/sync/vec.rs
+++ b/compiler/rustc_data_structures/src/sync/vec.rs
@@ -1,6 +1,6 @@
use std::marker::PhantomData;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
#[derive(Default)]
pub struct AppendOnlyIndexVec<I: Idx, T: Copy> {
diff --git a/compiler/rustc_data_structures/src/sync/worker_local.rs b/compiler/rustc_data_structures/src/sync/worker_local.rs
new file mode 100644
index 000000000..d61bb55be
--- /dev/null
+++ b/compiler/rustc_data_structures/src/sync/worker_local.rs
@@ -0,0 +1,173 @@
+use crate::sync::Lock;
+use std::cell::Cell;
+use std::cell::OnceCell;
+use std::ops::Deref;
+use std::ptr;
+use std::sync::Arc;
+
+#[cfg(parallel_compiler)]
+use {crate::cold_path, crate::sync::CacheAligned};
+
+/// A pointer to the `RegistryData` which uniquely identifies a registry.
+/// This identifier can be reused if the registry gets freed.
+#[derive(Clone, Copy, PartialEq)]
+struct RegistryId(*const RegistryData);
+
+impl RegistryId {
+ #[inline(always)]
+ /// Verifies that the current thread is associated with the registry and returns its unique
+ /// index within the registry. This panics if the current thread is not associated with this
+ /// registry.
+ ///
+ /// Note that there's a race possible where the identifer in `THREAD_DATA` could be reused
+ /// so this can succeed from a different registry.
+ #[cfg(parallel_compiler)]
+ fn verify(self) -> usize {
+ let (id, index) = THREAD_DATA.with(|data| (data.registry_id.get(), data.index.get()));
+
+ if id == self {
+ index
+ } else {
+ cold_path(|| panic!("Unable to verify registry association"))
+ }
+ }
+}
+
+struct RegistryData {
+ thread_limit: usize,
+ threads: Lock<usize>,
+}
+
+/// Represents a list of threads which can access worker locals.
+#[derive(Clone)]
+pub struct Registry(Arc<RegistryData>);
+
+thread_local! {
+ /// The registry associated with the thread.
+ /// This allows the `WorkerLocal` type to clone the registry in its constructor.
+ static REGISTRY: OnceCell<Registry> = OnceCell::new();
+}
+
+struct ThreadData {
+ registry_id: Cell<RegistryId>,
+ index: Cell<usize>,
+}
+
+thread_local! {
+ /// A thread local which contains the identifer of `REGISTRY` but allows for faster access.
+ /// It also holds the index of the current thread.
+ static THREAD_DATA: ThreadData = const { ThreadData {
+ registry_id: Cell::new(RegistryId(ptr::null())),
+ index: Cell::new(0),
+ }};
+}
+
+impl Registry {
+ /// Creates a registry which can hold up to `thread_limit` threads.
+ pub fn new(thread_limit: usize) -> Self {
+ Registry(Arc::new(RegistryData { thread_limit, threads: Lock::new(0) }))
+ }
+
+ /// Gets the registry associated with the current thread. Panics if there's no such registry.
+ pub fn current() -> Self {
+ REGISTRY.with(|registry| registry.get().cloned().expect("No assocated registry"))
+ }
+
+ /// Registers the current thread with the registry so worker locals can be used on it.
+ /// Panics if the thread limit is hit or if the thread already has an associated registry.
+ pub fn register(&self) {
+ let mut threads = self.0.threads.lock();
+ if *threads < self.0.thread_limit {
+ REGISTRY.with(|registry| {
+ if registry.get().is_some() {
+ drop(threads);
+ panic!("Thread already has a registry");
+ }
+ registry.set(self.clone()).ok();
+ THREAD_DATA.with(|data| {
+ data.registry_id.set(self.id());
+ data.index.set(*threads);
+ });
+ *threads += 1;
+ });
+ } else {
+ drop(threads);
+ panic!("Thread limit reached");
+ }
+ }
+
+ /// Gets the identifer of this registry.
+ fn id(&self) -> RegistryId {
+ RegistryId(&*self.0)
+ }
+}
+
+/// Holds worker local values for each possible thread in a registry. You can only access the
+/// worker local value through the `Deref` impl on the registry associated with the thread it was
+/// created on. It will panic otherwise.
+pub struct WorkerLocal<T> {
+ #[cfg(not(parallel_compiler))]
+ local: T,
+ #[cfg(parallel_compiler)]
+ locals: Box<[CacheAligned<T>]>,
+ #[cfg(parallel_compiler)]
+ registry: Registry,
+}
+
+// This is safe because the `deref` call will return a reference to a `T` unique to each thread
+// or it will panic for threads without an associated local. So there isn't a need for `T` to do
+// it's own synchronization. The `verify` method on `RegistryId` has an issue where the the id
+// can be reused, but `WorkerLocal` has a reference to `Registry` which will prevent any reuse.
+#[cfg(parallel_compiler)]
+unsafe impl<T: Send> Sync for WorkerLocal<T> {}
+
+impl<T> WorkerLocal<T> {
+ /// Creates a new worker local where the `initial` closure computes the
+ /// value this worker local should take for each thread in the registry.
+ #[inline]
+ pub fn new<F: FnMut(usize) -> T>(mut initial: F) -> WorkerLocal<T> {
+ #[cfg(parallel_compiler)]
+ {
+ let registry = Registry::current();
+ WorkerLocal {
+ locals: (0..registry.0.thread_limit).map(|i| CacheAligned(initial(i))).collect(),
+ registry,
+ }
+ }
+ #[cfg(not(parallel_compiler))]
+ {
+ WorkerLocal { local: initial(0) }
+ }
+ }
+
+ /// Returns the worker-local values for each thread
+ #[inline]
+ pub fn into_inner(self) -> impl Iterator<Item = T> {
+ #[cfg(parallel_compiler)]
+ {
+ self.locals.into_vec().into_iter().map(|local| local.0)
+ }
+ #[cfg(not(parallel_compiler))]
+ {
+ std::iter::once(self.local)
+ }
+ }
+}
+
+impl<T> Deref for WorkerLocal<T> {
+ type Target = T;
+
+ #[inline(always)]
+ #[cfg(not(parallel_compiler))]
+ fn deref(&self) -> &T {
+ &self.local
+ }
+
+ #[inline(always)]
+ #[cfg(parallel_compiler)]
+ fn deref(&self) -> &T {
+ // This is safe because `verify` will only return values less than
+ // `self.registry.thread_limit` which is the size of the `self.locals` array.
+ unsafe { &self.locals.get_unchecked(self.registry.id().verify()).0 }
+ }
+}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs
index 651bc556c..2914eece6 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr.rs
@@ -3,166 +3,281 @@
//! In order to utilize the pointer packing, you must have two types: a pointer,
//! and a tag.
//!
-//! The pointer must implement the `Pointer` trait, with the primary requirement
-//! being conversion to and from a usize. Note that the pointer must be
-//! dereferenceable, so raw pointers generally cannot implement the `Pointer`
-//! trait. This implies that the pointer must also be nonzero.
+//! The pointer must implement the [`Pointer`] trait, with the primary
+//! requirement being convertible to and from a raw pointer. Note that the
+//! pointer must be dereferenceable, so raw pointers generally cannot implement
+//! the [`Pointer`] trait. This implies that the pointer must also be non-null.
//!
-//! Many common pointer types already implement the `Pointer` trait.
+//! Many common pointer types already implement the [`Pointer`] trait.
//!
-//! The tag must implement the `Tag` trait. We assert that the tag and `Pointer`
-//! are compatible at compile time.
+//! The tag must implement the [`Tag`] trait.
+//!
+//! We assert that the tag and the [`Pointer`] types are compatible at compile
+//! time.
-use std::mem::ManuallyDrop;
use std::ops::Deref;
+use std::ptr::NonNull;
use std::rc::Rc;
use std::sync::Arc;
+use crate::aligned::Aligned;
+
mod copy;
mod drop;
+mod impl_tag;
pub use copy::CopyTaggedPtr;
pub use drop::TaggedPtr;
-/// This describes the pointer type encapsulated by TaggedPtr.
+/// This describes the pointer type encapsulated by [`TaggedPtr`] and
+/// [`CopyTaggedPtr`].
///
/// # Safety
///
-/// The usize returned from `into_usize` must be a valid, dereferenceable,
-/// pointer to `<Self as Deref>::Target`. Note that pointers to `Pointee` must
-/// be thin, even though `Pointee` may not be sized.
+/// The pointer returned from [`into_ptr`] must be a [valid], pointer to
+/// [`<Self as Deref>::Target`].
///
-/// Note that the returned pointer from `into_usize` should be castable to `&mut
-/// <Self as Deref>::Target` if `Pointer: DerefMut`.
+/// Note that if `Self` implements [`DerefMut`] the pointer returned from
+/// [`into_ptr`] must be valid for writes (and thus calling [`NonNull::as_mut`]
+/// on it must be safe).
///
-/// The BITS constant must be correct. At least `BITS` bits, least-significant,
-/// must be zero on all returned pointers from `into_usize`.
+/// The [`BITS`] constant must be correct. [`BITS`] least-significant bits,
+/// must be zero on all pointers returned from [`into_ptr`].
///
-/// For example, if the alignment of `Pointee` is 2, then `BITS` should be 1.
+/// For example, if the alignment of [`Self::Target`] is 2, then `BITS` should be 1.
+///
+/// [`BITS`]: Pointer::BITS
+/// [`into_ptr`]: Pointer::into_ptr
+/// [valid]: std::ptr#safety
+/// [`<Self as Deref>::Target`]: Deref::Target
+/// [`Self::Target`]: Deref::Target
+/// [`DerefMut`]: std::ops::DerefMut
pub unsafe trait Pointer: Deref {
+ /// Number of unused (always zero) **least-significant bits** in this
+ /// pointer, usually related to the pointees alignment.
+ ///
+ /// For example if [`BITS`] = `2`, then given `ptr = Self::into_ptr(..)`,
+ /// `ptr.addr() & 0b11 == 0` must be true.
+ ///
/// Most likely the value you want to use here is the following, unless
- /// your Pointee type is unsized (e.g., `ty::List<T>` in rustc) in which
- /// case you'll need to manually figure out what the right type to pass to
- /// align_of is.
+ /// your [`Self::Target`] type is unsized (e.g., `ty::List<T>` in rustc)
+ /// or your pointer is over/under aligned, in which case you'll need to
+ /// manually figure out what the right type to pass to [`bits_for`] is, or
+ /// what the value to set here.
///
- /// ```ignore UNSOLVED (what to do about the Self)
+ /// ```rust
/// # use std::ops::Deref;
- /// std::mem::align_of::<<Self as Deref>::Target>().trailing_zeros() as usize;
+ /// # use rustc_data_structures::tagged_ptr::bits_for;
+ /// # struct T;
+ /// # impl Deref for T { type Target = u8; fn deref(&self) -> &u8 { &0 } }
+ /// # impl T {
+ /// const BITS: u32 = bits_for::<<Self as Deref>::Target>();
+ /// # }
/// ```
- const BITS: usize;
- fn into_usize(self) -> usize;
+ ///
+ /// [`BITS`]: Pointer::BITS
+ /// [`Self::Target`]: Deref::Target
+ const BITS: u32;
- /// # Safety
+ /// Turns this pointer into a raw, non-null pointer.
+ ///
+ /// The inverse of this function is [`from_ptr`].
///
- /// The passed `ptr` must be returned from `into_usize`.
+ /// This function guarantees that the least-significant [`Self::BITS`] bits
+ /// are zero.
///
- /// This acts as `ptr::read` semantically, it should not be called more than
- /// once on non-`Copy` `Pointer`s.
- unsafe fn from_usize(ptr: usize) -> Self;
+ /// [`from_ptr`]: Pointer::from_ptr
+ /// [`Self::BITS`]: Pointer::BITS
+ fn into_ptr(self) -> NonNull<Self::Target>;
- /// This provides a reference to the `Pointer` itself, rather than the
- /// `Deref::Target`. It is used for cases where we want to call methods that
- /// may be implement differently for the Pointer than the Pointee (e.g.,
- /// `Rc::clone` vs cloning the inner value).
+ /// Re-creates the original pointer, from a raw pointer returned by [`into_ptr`].
///
/// # Safety
///
- /// The passed `ptr` must be returned from `into_usize`.
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R;
+ /// The passed `ptr` must be returned from [`into_ptr`].
+ ///
+ /// This acts as [`ptr::read::<Self>()`] semantically, it should not be called more than
+ /// once on non-[`Copy`] `Pointer`s.
+ ///
+ /// [`into_ptr`]: Pointer::into_ptr
+ /// [`ptr::read::<Self>()`]: std::ptr::read
+ unsafe fn from_ptr(ptr: NonNull<Self::Target>) -> Self;
}
-/// This describes tags that the `TaggedPtr` struct can hold.
+/// This describes tags that the [`TaggedPtr`] struct can hold.
///
/// # Safety
///
-/// The BITS constant must be correct.
+/// The [`BITS`] constant must be correct.
///
-/// No more than `BITS` least significant bits may be set in the returned usize.
+/// No more than [`BITS`] least-significant bits may be set in the returned usize.
+///
+/// [`BITS`]: Tag::BITS
pub unsafe trait Tag: Copy {
- const BITS: usize;
+ /// Number of least-significant bits in the return value of [`into_usize`]
+ /// which may be non-zero. In other words this is the bit width of the
+ /// value.
+ ///
+ /// [`into_usize`]: Tag::into_usize
+ const BITS: u32;
+ /// Turns this tag into an integer.
+ ///
+ /// The inverse of this function is [`from_usize`].
+ ///
+ /// This function guarantees that only the least-significant [`Self::BITS`]
+ /// bits can be non-zero.
+ ///
+ /// [`from_usize`]: Tag::from_usize
+ /// [`Self::BITS`]: Tag::BITS
fn into_usize(self) -> usize;
+ /// Re-creates the tag from the integer returned by [`into_usize`].
+ ///
/// # Safety
///
- /// The passed `tag` must be returned from `into_usize`.
+ /// The passed `tag` must be returned from [`into_usize`].
+ ///
+ /// [`into_usize`]: Tag::into_usize
unsafe fn from_usize(tag: usize) -> Self;
}
-unsafe impl<T> Pointer for Box<T> {
- const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
- #[inline]
- fn into_usize(self) -> usize {
- Box::into_raw(self) as usize
+/// Returns the number of bits available for use for tags in a pointer to `T`
+/// (this is based on `T`'s alignment).
+pub const fn bits_for<T: ?Sized + Aligned>() -> u32 {
+ crate::aligned::align_of::<T>().as_nonzero().trailing_zeros()
+}
+
+/// Returns the correct [`Tag::BITS`] constant for a set of tag values.
+pub const fn bits_for_tags(mut tags: &[usize]) -> u32 {
+ let mut bits = 0;
+
+ while let &[tag, ref rest @ ..] = tags {
+ tags = rest;
+
+ // bits required to represent `tag`,
+ // position of the most significant 1
+ let b = usize::BITS - tag.leading_zeros();
+ if b > bits {
+ bits = b;
+ }
}
+
+ bits
+}
+
+unsafe impl<T: ?Sized + Aligned> Pointer for Box<T> {
+ const BITS: u32 = bits_for::<Self::Target>();
+
#[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- Box::from_raw(ptr as *mut T)
+ fn into_ptr(self) -> NonNull<T> {
+ // Safety: pointers from `Box::into_raw` are valid & non-null
+ unsafe { NonNull::new_unchecked(Box::into_raw(self)) }
}
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- let raw = ManuallyDrop::new(Self::from_usize(ptr));
- f(&raw)
+
+ #[inline]
+ unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
+ // Safety: `ptr` comes from `into_ptr` which calls `Box::into_raw`
+ unsafe { Box::from_raw(ptr.as_ptr()) }
}
}
-unsafe impl<T> Pointer for Rc<T> {
- const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+unsafe impl<T: ?Sized + Aligned> Pointer for Rc<T> {
+ const BITS: u32 = bits_for::<Self::Target>();
+
#[inline]
- fn into_usize(self) -> usize {
- Rc::into_raw(self) as usize
+ fn into_ptr(self) -> NonNull<T> {
+ // Safety: pointers from `Rc::into_raw` are valid & non-null
+ unsafe { NonNull::new_unchecked(Rc::into_raw(self).cast_mut()) }
}
+
#[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- Rc::from_raw(ptr as *const T)
- }
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- let raw = ManuallyDrop::new(Self::from_usize(ptr));
- f(&raw)
+ unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
+ // Safety: `ptr` comes from `into_ptr` which calls `Rc::into_raw`
+ unsafe { Rc::from_raw(ptr.as_ptr()) }
}
}
-unsafe impl<T> Pointer for Arc<T> {
- const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+unsafe impl<T: ?Sized + Aligned> Pointer for Arc<T> {
+ const BITS: u32 = bits_for::<Self::Target>();
+
#[inline]
- fn into_usize(self) -> usize {
- Arc::into_raw(self) as usize
+ fn into_ptr(self) -> NonNull<T> {
+ // Safety: pointers from `Arc::into_raw` are valid & non-null
+ unsafe { NonNull::new_unchecked(Arc::into_raw(self).cast_mut()) }
}
+
#[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- Arc::from_raw(ptr as *const T)
- }
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- let raw = ManuallyDrop::new(Self::from_usize(ptr));
- f(&raw)
+ unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
+ // Safety: `ptr` comes from `into_ptr` which calls `Arc::into_raw`
+ unsafe { Arc::from_raw(ptr.as_ptr()) }
}
}
-unsafe impl<'a, T: 'a> Pointer for &'a T {
- const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a T {
+ const BITS: u32 = bits_for::<Self::Target>();
+
#[inline]
- fn into_usize(self) -> usize {
- self as *const T as usize
+ fn into_ptr(self) -> NonNull<T> {
+ NonNull::from(self)
}
+
#[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- &*(ptr as *const T)
- }
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- f(&*(&ptr as *const usize as *const Self))
+ unsafe fn from_ptr(ptr: NonNull<T>) -> Self {
+ // Safety:
+ // `ptr` comes from `into_ptr` which gets the pointer from a reference
+ unsafe { ptr.as_ref() }
}
}
-unsafe impl<'a, T: 'a> Pointer for &'a mut T {
- const BITS: usize = std::mem::align_of::<T>().trailing_zeros() as usize;
+unsafe impl<'a, T: 'a + ?Sized + Aligned> Pointer for &'a mut T {
+ const BITS: u32 = bits_for::<Self::Target>();
+
#[inline]
- fn into_usize(self) -> usize {
- self as *mut T as usize
+ fn into_ptr(self) -> NonNull<T> {
+ NonNull::from(self)
}
+
#[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- &mut *(ptr as *mut T)
+ unsafe fn from_ptr(mut ptr: NonNull<T>) -> Self {
+ // Safety:
+ // `ptr` comes from `into_ptr` which gets the pointer from a reference
+ unsafe { ptr.as_mut() }
+ }
+}
+
+/// A tag type used in [`CopyTaggedPtr`] and [`TaggedPtr`] tests.
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[cfg(test)]
+enum Tag2 {
+ B00 = 0b00,
+ B01 = 0b01,
+ B10 = 0b10,
+ B11 = 0b11,
+}
+
+#[cfg(test)]
+unsafe impl Tag for Tag2 {
+ const BITS: u32 = 2;
+
+ fn into_usize(self) -> usize {
+ self as _
}
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- f(&*(&ptr as *const usize as *const Self))
+
+ unsafe fn from_usize(tag: usize) -> Self {
+ match tag {
+ 0b00 => Tag2::B00,
+ 0b01 => Tag2::B01,
+ 0b10 => Tag2::B10,
+ 0b11 => Tag2::B11,
+ _ => unreachable!(),
+ }
+ }
+}
+
+#[cfg(test)]
+impl<HCX> crate::stable_hasher::HashStable<HCX> for Tag2 {
+ fn hash_stable(&self, hcx: &mut HCX, hasher: &mut crate::stable_hasher::StableHasher) {
+ (*self as u8).hash_stable(hcx, hasher);
}
}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
index e1d3e0bd3..e893a2c78 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs
@@ -1,78 +1,94 @@
use super::{Pointer, Tag};
use crate::stable_hasher::{HashStable, StableHasher};
use std::fmt;
+use std::hash::{Hash, Hasher};
use std::marker::PhantomData;
+use std::mem::ManuallyDrop;
use std::num::NonZeroUsize;
+use std::ops::{Deref, DerefMut};
+use std::ptr::NonNull;
-/// A `Copy` TaggedPtr.
+/// A [`Copy`] tagged pointer.
///
-/// You should use this instead of the `TaggedPtr` type in all cases where
-/// `P: Copy`.
+/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer.
+///
+/// You should use this instead of the [`TaggedPtr`] type in all cases where
+/// `P` implements [`Copy`].
///
/// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without
-/// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that,
-/// wrap the TaggedPtr.
+/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`];
+/// if you want that, wrap the [`CopyTaggedPtr`].
+///
+/// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr
pub struct CopyTaggedPtr<P, T, const COMPARE_PACKED: bool>
where
P: Pointer,
T: Tag,
{
- packed: NonZeroUsize,
- data: PhantomData<(P, T)>,
-}
-
-impl<P, T, const COMPARE_PACKED: bool> Copy for CopyTaggedPtr<P, T, COMPARE_PACKED>
-where
- P: Pointer,
- T: Tag,
- P: Copy,
-{
-}
-
-impl<P, T, const COMPARE_PACKED: bool> Clone for CopyTaggedPtr<P, T, COMPARE_PACKED>
-where
- P: Pointer,
- T: Tag,
- P: Copy,
-{
- fn clone(&self) -> Self {
- *self
- }
+ /// This is semantically a pair of `pointer: P` and `tag: T` fields,
+ /// however we pack them in a single pointer, to save space.
+ ///
+ /// We pack the tag into the **most**-significant bits of the pointer to
+ /// ease retrieval of the value. A left shift is a multiplication and
+ /// those are embeddable in instruction encoding, for example:
+ ///
+ /// ```asm
+ /// // (<https://godbolt.org/z/jqcYPWEr3>)
+ /// example::shift_read3:
+ /// mov eax, dword ptr [8*rdi]
+ /// ret
+ ///
+ /// example::mask_read3:
+ /// and rdi, -8
+ /// mov eax, dword ptr [rdi]
+ /// ret
+ /// ```
+ ///
+ /// This is ASM outputted by rustc for reads of values behind tagged
+ /// pointers for different approaches of tagging:
+ /// - `shift_read3` uses `<< 3` (the tag is in the most-significant bits)
+ /// - `mask_read3` uses `& !0b111` (the tag is in the least-significant bits)
+ ///
+ /// The shift approach thus produces less instructions and is likely faster
+ /// (see <https://godbolt.org/z/Y913sMdWb>).
+ ///
+ /// Encoding diagram:
+ /// ```text
+ /// [ packed.addr ]
+ /// [ tag ] [ pointer.addr >> T::BITS ] <-- usize::BITS - T::BITS bits
+ /// ^
+ /// |
+ /// T::BITS bits
+ /// ```
+ ///
+ /// The tag can be retrieved by `packed.addr() >> T::BITS` and the pointer
+ /// can be retrieved by `packed.map_addr(|addr| addr << T::BITS)`.
+ packed: NonNull<P::Target>,
+ tag_ghost: PhantomData<T>,
}
-// We pack the tag into the *upper* bits of the pointer to ease retrieval of the
-// value; a left shift is a multiplication and those are embeddable in
-// instruction encoding.
-impl<P, T, const COMPARE_PACKED: bool> CopyTaggedPtr<P, T, COMPARE_PACKED>
+// Note that even though `CopyTaggedPtr` is only really expected to work with
+// `P: Copy`, can't add `P: Copy` bound, because `CopyTaggedPtr` is used in the
+// `TaggedPtr`'s implementation.
+impl<P, T, const CP: bool> CopyTaggedPtr<P, T, CP>
where
P: Pointer,
T: Tag,
{
- const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS;
- const ASSERTION: () = {
- assert!(T::BITS <= P::BITS);
- // Used for the transmute_copy's below
- assert!(std::mem::size_of::<&P::Target>() == std::mem::size_of::<usize>());
- };
-
+ /// Tags `pointer` with `tag`.
+ ///
+ /// Note that this leaks `pointer`: it won't be dropped when
+ /// `CopyTaggedPtr` is dropped. If you have a pointer with a significant
+ /// drop, use [`TaggedPtr`] instead.
+ ///
+ /// [`TaggedPtr`]: crate::tagged_ptr::TaggedPtr
+ #[inline]
pub fn new(pointer: P, tag: T) -> Self {
- // Trigger assert!
- let () = Self::ASSERTION;
- let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT;
-
- Self {
- // SAFETY: We know that the pointer is non-null, as it must be
- // dereferenceable per `Pointer` safety contract.
- packed: unsafe {
- NonZeroUsize::new_unchecked((P::into_usize(pointer) >> T::BITS) | packed_tag)
- },
- data: PhantomData,
- }
+ Self { packed: Self::pack(P::into_ptr(pointer), tag), tag_ghost: PhantomData }
}
- pub(super) fn pointer_raw(&self) -> usize {
- self.packed.get() << T::BITS
- }
+ /// Retrieves the pointer.
+ #[inline]
pub fn pointer(self) -> P
where
P: Copy,
@@ -81,66 +97,143 @@ where
//
// Note that this isn't going to double-drop or anything because we have
// P: Copy
- unsafe { P::from_usize(self.pointer_raw()) }
- }
- pub fn pointer_ref(&self) -> &P::Target {
- // SAFETY: pointer_raw returns the original pointer
- unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
- }
- pub fn pointer_mut(&mut self) -> &mut P::Target
- where
- P: std::ops::DerefMut,
- {
- // SAFETY: pointer_raw returns the original pointer
- unsafe { std::mem::transmute_copy(&self.pointer_raw()) }
+ unsafe { P::from_ptr(self.pointer_raw()) }
}
+
+ /// Retrieves the tag.
#[inline]
pub fn tag(&self) -> T {
- unsafe { T::from_usize(self.packed.get() >> Self::TAG_BIT_SHIFT) }
+ // Unpack the tag, according to the `self.packed` encoding scheme
+ let tag = self.packed.addr().get() >> Self::TAG_BIT_SHIFT;
+
+ // Safety:
+ // The shift retrieves the original value from `T::into_usize`,
+ // satisfying `T::from_usize`'s preconditions.
+ unsafe { T::from_usize(tag) }
}
+
+ /// Sets the tag to a new value.
#[inline]
pub fn set_tag(&mut self, tag: T) {
- let mut packed = self.packed.get();
- let new_tag = T::into_usize(tag) << Self::TAG_BIT_SHIFT;
- let tag_mask = (1 << T::BITS) - 1;
- packed &= !(tag_mask << Self::TAG_BIT_SHIFT);
- packed |= new_tag;
- self.packed = unsafe { NonZeroUsize::new_unchecked(packed) };
+ self.packed = Self::pack(self.pointer_raw(), tag);
+ }
+
+ const TAG_BIT_SHIFT: u32 = usize::BITS - T::BITS;
+ const ASSERTION: () = { assert!(T::BITS <= P::BITS) };
+
+ /// Pack pointer `ptr` that comes from [`P::into_ptr`] with a `tag`,
+ /// according to `self.packed` encoding scheme.
+ ///
+ /// [`P::into_ptr`]: Pointer::into_ptr
+ #[inline]
+ fn pack(ptr: NonNull<P::Target>, tag: T) -> NonNull<P::Target> {
+ // Trigger assert!
+ let () = Self::ASSERTION;
+
+ let packed_tag = tag.into_usize() << Self::TAG_BIT_SHIFT;
+
+ ptr.map_addr(|addr| {
+ // Safety:
+ // - The pointer is `NonNull` => it's address is `NonZeroUsize`
+ // - `P::BITS` least significant bits are always zero (`Pointer` contract)
+ // - `T::BITS <= P::BITS` (from `Self::ASSERTION`)
+ //
+ // Thus `addr >> T::BITS` is guaranteed to be non-zero.
+ //
+ // `{non_zero} | packed_tag` can't make the value zero.
+
+ let packed = (addr.get() >> T::BITS) | packed_tag;
+ unsafe { NonZeroUsize::new_unchecked(packed) }
+ })
}
+
+ /// Retrieves the original raw pointer from `self.packed`.
+ #[inline]
+ pub(super) fn pointer_raw(&self) -> NonNull<P::Target> {
+ self.packed.map_addr(|addr| unsafe { NonZeroUsize::new_unchecked(addr.get() << T::BITS) })
+ }
+
+ /// This provides a reference to the `P` pointer itself, rather than the
+ /// `Deref::Target`. It is used for cases where we want to call methods
+ /// that may be implement differently for the Pointer than the Pointee
+ /// (e.g., `Rc::clone` vs cloning the inner value).
+ pub(super) fn with_pointer_ref<R>(&self, f: impl FnOnce(&P) -> R) -> R {
+ // Safety:
+ // - `self.raw.pointer_raw()` is originally returned from `P::into_ptr`
+ // and as such is valid for `P::from_ptr`.
+ // - This also allows us to not care whatever `f` panics or not.
+ // - Even though we create a copy of the pointer, we store it inside
+ // `ManuallyDrop` and only access it by-ref, so we don't double-drop.
+ //
+ // Semantically this is just `f(&self.pointer)` (where `self.pointer`
+ // is non-packed original pointer).
+ //
+ // Note that even though `CopyTaggedPtr` is only really expected to
+ // work with `P: Copy`, we have to assume `P: ?Copy`, because
+ // `CopyTaggedPtr` is used in the `TaggedPtr`'s implementation.
+ let ptr = unsafe { ManuallyDrop::new(P::from_ptr(self.pointer_raw())) };
+ f(&ptr)
+ }
+}
+
+impl<P, T, const CP: bool> Copy for CopyTaggedPtr<P, T, CP>
+where
+ P: Pointer + Copy,
+ T: Tag,
+{
}
-impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for CopyTaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> Clone for CopyTaggedPtr<P, T, CP>
+where
+ P: Pointer + Copy,
+ T: Tag,
+{
+ #[inline]
+ fn clone(&self) -> Self {
+ *self
+ }
+}
+
+impl<P, T, const CP: bool> Deref for CopyTaggedPtr<P, T, CP>
where
P: Pointer,
T: Tag,
{
type Target = P::Target;
+
+ #[inline]
fn deref(&self) -> &Self::Target {
- self.pointer_ref()
+ // Safety:
+ // `pointer_raw` returns the original pointer from `P::into_ptr` which,
+ // by the `Pointer`'s contract, must be valid.
+ unsafe { self.pointer_raw().as_ref() }
}
}
-impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for CopyTaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> DerefMut for CopyTaggedPtr<P, T, CP>
where
- P: Pointer + std::ops::DerefMut,
+ P: Pointer + DerefMut,
T: Tag,
{
+ #[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
- self.pointer_mut()
+ // Safety:
+ // `pointer_raw` returns the original pointer from `P::into_ptr` which,
+ // by the `Pointer`'s contract, must be valid for writes if
+ // `P: DerefMut`.
+ unsafe { self.pointer_raw().as_mut() }
}
}
-impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for CopyTaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> fmt::Debug for CopyTaggedPtr<P, T, CP>
where
- P: Pointer,
- P::Target: fmt::Debug,
+ P: Pointer + fmt::Debug,
T: Tag + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("CopyTaggedPtr")
- .field("pointer", &self.pointer_ref())
- .field("tag", &self.tag())
- .finish()
+ self.with_pointer_ref(|ptr| {
+ f.debug_struct("CopyTaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish()
+ })
}
}
@@ -149,6 +242,7 @@ where
P: Pointer,
T: Tag,
{
+ #[inline]
fn eq(&self, other: &Self) -> bool {
self.packed == other.packed
}
@@ -161,25 +255,74 @@ where
{
}
-impl<P, T> std::hash::Hash for CopyTaggedPtr<P, T, true>
+impl<P, T> Hash for CopyTaggedPtr<P, T, true>
where
P: Pointer,
T: Tag,
{
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
self.packed.hash(state);
}
}
-impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for CopyTaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, HCX, const CP: bool> HashStable<HCX> for CopyTaggedPtr<P, T, CP>
where
P: Pointer + HashStable<HCX>,
T: Tag + HashStable<HCX>,
{
fn hash_stable(&self, hcx: &mut HCX, hasher: &mut StableHasher) {
- unsafe {
- Pointer::with_ref(self.pointer_raw(), |p: &P| p.hash_stable(hcx, hasher));
- }
+ self.with_pointer_ref(|ptr| ptr.hash_stable(hcx, hasher));
self.tag().hash_stable(hcx, hasher);
}
}
+
+// Safety:
+// `CopyTaggedPtr<P, T, ..>` is semantically just `{ ptr: P, tag: T }`, as such
+// it's ok to implement `Sync` as long as `P: Sync, T: Sync`
+unsafe impl<P, T, const CP: bool> Sync for CopyTaggedPtr<P, T, CP>
+where
+ P: Sync + Pointer,
+ T: Sync + Tag,
+{
+}
+
+// Safety:
+// `CopyTaggedPtr<P, T, ..>` is semantically just `{ ptr: P, tag: T }`, as such
+// it's ok to implement `Send` as long as `P: Send, T: Send`
+unsafe impl<P, T, const CP: bool> Send for CopyTaggedPtr<P, T, CP>
+where
+ P: Send + Pointer,
+ T: Send + Tag,
+{
+}
+
+/// Test that `new` does not compile if there is not enough alignment for the
+/// tag in the pointer.
+///
+/// ```compile_fail,E0080
+/// use rustc_data_structures::tagged_ptr::{CopyTaggedPtr, Tag};
+///
+/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
+///
+/// unsafe impl Tag for Tag2 {
+/// const BITS: u32 = 2;
+///
+/// fn into_usize(self) -> usize { todo!() }
+/// unsafe fn from_usize(tag: usize) -> Self { todo!() }
+/// }
+///
+/// let value = 12u16;
+/// let reference = &value;
+/// let tag = Tag2::B01;
+///
+/// let _ptr = CopyTaggedPtr::<_, _, true>::new(reference, tag);
+/// ```
+// For some reason miri does not get the compile error
+// probably it `check`s instead of `build`ing?
+#[cfg(not(miri))]
+const _: () = ();
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
new file mode 100644
index 000000000..bfcc2e603
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/copy/tests.rs
@@ -0,0 +1,50 @@
+use std::ptr;
+
+use crate::stable_hasher::{HashStable, StableHasher};
+use crate::tagged_ptr::{CopyTaggedPtr, Pointer, Tag, Tag2};
+
+#[test]
+fn smoke() {
+ let value = 12u32;
+ let reference = &value;
+ let tag = Tag2::B01;
+
+ let ptr = tag_ptr(reference, tag);
+
+ assert_eq!(ptr.tag(), tag);
+ assert_eq!(*ptr, 12);
+ assert!(ptr::eq(ptr.pointer(), reference));
+
+ let copy = ptr;
+
+ let mut ptr = ptr;
+ ptr.set_tag(Tag2::B00);
+ assert_eq!(ptr.tag(), Tag2::B00);
+
+ assert_eq!(copy.tag(), tag);
+ assert_eq!(*copy, 12);
+ assert!(ptr::eq(copy.pointer(), reference));
+}
+
+#[test]
+fn stable_hash_hashes_as_tuple() {
+ let hash_packed = {
+ let mut hasher = StableHasher::new();
+ tag_ptr(&12, Tag2::B11).hash_stable(&mut (), &mut hasher);
+
+ hasher.finalize()
+ };
+
+ let hash_tupled = {
+ let mut hasher = StableHasher::new();
+ (&12, Tag2::B11).hash_stable(&mut (), &mut hasher);
+ hasher.finalize()
+ };
+
+ assert_eq!(hash_packed, hash_tupled);
+}
+
+/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
+fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> CopyTaggedPtr<P, T, true> {
+ CopyTaggedPtr::new(ptr, tag)
+}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
index b0315c93d..4e42b5b4a 100644
--- a/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs
@@ -1,14 +1,21 @@
-use super::{Pointer, Tag};
-use crate::stable_hasher::{HashStable, StableHasher};
use std::fmt;
+use std::hash::{Hash, Hasher};
+use std::ops::{Deref, DerefMut};
use super::CopyTaggedPtr;
+use super::{Pointer, Tag};
+use crate::stable_hasher::{HashStable, StableHasher};
-/// A TaggedPtr implementing `Drop`.
+/// A tagged pointer that supports pointers that implement [`Drop`].
+///
+/// This is essentially `{ pointer: P, tag: T }` packed in a single pointer.
+///
+/// You should use [`CopyTaggedPtr`] instead of the this type in all cases
+/// where `P` implements [`Copy`].
///
/// If `COMPARE_PACKED` is true, then the pointers will be compared and hashed without
-/// unpacking. Otherwise we don't implement PartialEq/Eq/Hash; if you want that,
-/// wrap the TaggedPtr.
+/// unpacking. Otherwise we don't implement [`PartialEq`], [`Eq`] and [`Hash`];
+/// if you want that, wrap the [`TaggedPtr`].
pub struct TaggedPtr<P, T, const COMPARE_PACKED: bool>
where
P: Pointer,
@@ -17,58 +24,67 @@ where
raw: CopyTaggedPtr<P, T, COMPARE_PACKED>,
}
-impl<P, T, const COMPARE_PACKED: bool> Clone for TaggedPtr<P, T, COMPARE_PACKED>
-where
- P: Pointer + Clone,
- T: Tag,
-{
- fn clone(&self) -> Self {
- unsafe { Self::new(P::with_ref(self.raw.pointer_raw(), |p| p.clone()), self.raw.tag()) }
- }
-}
-
-// We pack the tag into the *upper* bits of the pointer to ease retrieval of the
-// value; a right shift is a multiplication and those are embeddable in
-// instruction encoding.
-impl<P, T, const COMPARE_PACKED: bool> TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> TaggedPtr<P, T, CP>
where
P: Pointer,
T: Tag,
{
+ /// Tags `pointer` with `tag`.
+ #[inline]
pub fn new(pointer: P, tag: T) -> Self {
TaggedPtr { raw: CopyTaggedPtr::new(pointer, tag) }
}
- pub fn pointer_ref(&self) -> &P::Target {
- self.raw.pointer_ref()
- }
+ /// Retrieves the tag.
+ #[inline]
pub fn tag(&self) -> T {
self.raw.tag()
}
+
+ /// Sets the tag to a new value.
+ #[inline]
+ pub fn set_tag(&mut self, tag: T) {
+ self.raw.set_tag(tag)
+ }
+}
+
+impl<P, T, const CP: bool> Clone for TaggedPtr<P, T, CP>
+where
+ P: Pointer + Clone,
+ T: Tag,
+{
+ fn clone(&self) -> Self {
+ let ptr = self.raw.with_pointer_ref(P::clone);
+
+ Self::new(ptr, self.tag())
+ }
}
-impl<P, T, const COMPARE_PACKED: bool> std::ops::Deref for TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> Deref for TaggedPtr<P, T, CP>
where
P: Pointer,
T: Tag,
{
type Target = P::Target;
+
+ #[inline]
fn deref(&self) -> &Self::Target {
- self.raw.pointer_ref()
+ self.raw.deref()
}
}
-impl<P, T, const COMPARE_PACKED: bool> std::ops::DerefMut for TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> DerefMut for TaggedPtr<P, T, CP>
where
- P: Pointer + std::ops::DerefMut,
+ P: Pointer + DerefMut,
T: Tag,
{
+ #[inline]
fn deref_mut(&mut self) -> &mut Self::Target {
- self.raw.pointer_mut()
+ self.raw.deref_mut()
}
}
-impl<P, T, const COMPARE_PACKED: bool> Drop for TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> Drop for TaggedPtr<P, T, CP>
where
P: Pointer,
T: Tag,
@@ -76,22 +92,20 @@ where
fn drop(&mut self) {
// No need to drop the tag, as it's Copy
unsafe {
- drop(P::from_usize(self.raw.pointer_raw()));
+ drop(P::from_ptr(self.raw.pointer_raw()));
}
}
}
-impl<P, T, const COMPARE_PACKED: bool> fmt::Debug for TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, const CP: bool> fmt::Debug for TaggedPtr<P, T, CP>
where
- P: Pointer,
- P::Target: fmt::Debug,
+ P: Pointer + fmt::Debug,
T: Tag + fmt::Debug,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.debug_struct("TaggedPtr")
- .field("pointer", &self.pointer_ref())
- .field("tag", &self.tag())
- .finish()
+ self.raw.with_pointer_ref(|ptr| {
+ f.debug_struct("TaggedPtr").field("pointer", ptr).field("tag", &self.tag()).finish()
+ })
}
}
@@ -100,6 +114,7 @@ where
P: Pointer,
T: Tag,
{
+ #[inline]
fn eq(&self, other: &Self) -> bool {
self.raw.eq(&other.raw)
}
@@ -112,17 +127,18 @@ where
{
}
-impl<P, T> std::hash::Hash for TaggedPtr<P, T, true>
+impl<P, T> Hash for TaggedPtr<P, T, true>
where
P: Pointer,
T: Tag,
{
- fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ #[inline]
+ fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.hash(state);
}
}
-impl<P, T, HCX, const COMPARE_PACKED: bool> HashStable<HCX> for TaggedPtr<P, T, COMPARE_PACKED>
+impl<P, T, HCX, const CP: bool> HashStable<HCX> for TaggedPtr<P, T, CP>
where
P: Pointer + HashStable<HCX>,
T: Tag + HashStable<HCX>,
@@ -131,3 +147,33 @@ where
self.raw.hash_stable(hcx, hasher);
}
}
+
+/// Test that `new` does not compile if there is not enough alignment for the
+/// tag in the pointer.
+///
+/// ```compile_fail,E0080
+/// use rustc_data_structures::tagged_ptr::{TaggedPtr, Tag};
+///
+/// #[derive(Copy, Clone, Debug, PartialEq, Eq)]
+/// enum Tag2 { B00 = 0b00, B01 = 0b01, B10 = 0b10, B11 = 0b11 };
+///
+/// unsafe impl Tag for Tag2 {
+/// const BITS: u32 = 2;
+///
+/// fn into_usize(self) -> usize { todo!() }
+/// unsafe fn from_usize(tag: usize) -> Self { todo!() }
+/// }
+///
+/// let value = 12u16;
+/// let reference = &value;
+/// let tag = Tag2::B01;
+///
+/// let _ptr = TaggedPtr::<_, _, true>::new(reference, tag);
+/// ```
+// For some reason miri does not get the compile error
+// probably it `check`s instead of `build`ing?
+#[cfg(not(miri))]
+const _: () = ();
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
new file mode 100644
index 000000000..2c17d678d
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/drop/tests.rs
@@ -0,0 +1,71 @@
+use std::{ptr, sync::Arc};
+
+use crate::tagged_ptr::{Pointer, Tag, Tag2, TaggedPtr};
+
+#[test]
+fn smoke() {
+ let value = 12u32;
+ let reference = &value;
+ let tag = Tag2::B01;
+
+ let ptr = tag_ptr(reference, tag);
+
+ assert_eq!(ptr.tag(), tag);
+ assert_eq!(*ptr, 12);
+
+ let clone = ptr.clone();
+ assert_eq!(clone.tag(), tag);
+ assert_eq!(*clone, 12);
+
+ let mut ptr = ptr;
+ ptr.set_tag(Tag2::B00);
+ assert_eq!(ptr.tag(), Tag2::B00);
+
+ assert_eq!(clone.tag(), tag);
+ assert_eq!(*clone, 12);
+ assert!(ptr::eq(&*ptr, &*clone))
+}
+
+#[test]
+fn boxed() {
+ let value = 12u32;
+ let boxed = Box::new(value);
+ let tag = Tag2::B01;
+
+ let ptr = tag_ptr(boxed, tag);
+
+ assert_eq!(ptr.tag(), tag);
+ assert_eq!(*ptr, 12);
+
+ let clone = ptr.clone();
+ assert_eq!(clone.tag(), tag);
+ assert_eq!(*clone, 12);
+
+ let mut ptr = ptr;
+ ptr.set_tag(Tag2::B00);
+ assert_eq!(ptr.tag(), Tag2::B00);
+
+ assert_eq!(clone.tag(), tag);
+ assert_eq!(*clone, 12);
+ assert!(!ptr::eq(&*ptr, &*clone))
+}
+
+#[test]
+fn arclones() {
+ let value = 12u32;
+ let arc = Arc::new(value);
+ let tag = Tag2::B01;
+
+ let ptr = tag_ptr(arc, tag);
+
+ assert_eq!(ptr.tag(), tag);
+ assert_eq!(*ptr, 12);
+
+ let clone = ptr.clone();
+ assert!(ptr::eq(&*ptr, &*clone))
+}
+
+/// Helper to create tagged pointers without specifying `COMPARE_PACKED` if it does not matter.
+fn tag_ptr<P: Pointer, T: Tag>(ptr: P, tag: T) -> TaggedPtr<P, T, true> {
+ TaggedPtr::new(ptr, tag)
+}
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
new file mode 100644
index 000000000..cb7f7d318
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag.rs
@@ -0,0 +1,144 @@
+/// Implements [`Tag`] for a given type.
+///
+/// You can use `impl_tag` on structs and enums.
+/// You need to specify the type and all its possible values,
+/// which can only be paths with optional fields.
+///
+/// [`Tag`]: crate::tagged_ptr::Tag
+///
+/// # Examples
+///
+/// Basic usage:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// use rustc_data_structures::{impl_tag, tagged_ptr::Tag};
+///
+/// #[derive(Copy, Clone, PartialEq, Debug)]
+/// enum SomeTag {
+/// A,
+/// B,
+/// X { v: bool },
+/// Y(bool, bool),
+/// }
+///
+/// impl_tag! {
+/// // The type for which the `Tag` will be implemented
+/// impl Tag for SomeTag;
+/// // You need to specify all possible tag values:
+/// SomeTag::A, // 0
+/// SomeTag::B, // 1
+/// // For variants with fields, you need to specify the fields:
+/// SomeTag::X { v: true }, // 2
+/// SomeTag::X { v: false }, // 3
+/// // For tuple variants use named syntax:
+/// SomeTag::Y { 0: true, 1: true }, // 4
+/// SomeTag::Y { 0: false, 1: true }, // 5
+/// SomeTag::Y { 0: true, 1: false }, // 6
+/// SomeTag::Y { 0: false, 1: false }, // 7
+/// }
+///
+/// // Tag values are assigned in order:
+/// assert_eq!(SomeTag::A.into_usize(), 0);
+/// assert_eq!(SomeTag::X { v: false }.into_usize(), 3);
+/// assert_eq!(SomeTag::Y(false, true).into_usize(), 5);
+///
+/// assert_eq!(unsafe { SomeTag::from_usize(1) }, SomeTag::B);
+/// assert_eq!(unsafe { SomeTag::from_usize(2) }, SomeTag::X { v: true });
+/// assert_eq!(unsafe { SomeTag::from_usize(7) }, SomeTag::Y(false, false));
+/// ```
+///
+/// Structs are supported:
+///
+/// ```
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// struct Flags { a: bool, b: bool }
+///
+/// impl_tag! {
+/// impl Tag for Flags;
+/// Flags { a: true, b: true },
+/// Flags { a: false, b: true },
+/// Flags { a: true, b: false },
+/// Flags { a: false, b: false },
+/// }
+/// ```
+///
+/// Not specifying all values results in a compile error:
+///
+/// ```compile_fail,E0004
+/// #![feature(macro_metavar_expr)]
+/// # use rustc_data_structures::impl_tag;
+/// #[derive(Copy, Clone)]
+/// enum E {
+/// A,
+/// B,
+/// }
+///
+/// impl_tag! {
+/// impl Tag for E;
+/// E::A,
+/// }
+/// ```
+#[macro_export]
+macro_rules! impl_tag {
+ (
+ impl Tag for $Self:ty;
+ $(
+ $($path:ident)::* $( { $( $fields:tt )* })?,
+ )*
+ ) => {
+ // Safety:
+ // `bits_for_tags` is called on the same `${index()}`-es as
+ // `into_usize` returns, thus `BITS` constant is correct.
+ unsafe impl $crate::tagged_ptr::Tag for $Self {
+ const BITS: u32 = $crate::tagged_ptr::bits_for_tags(&[
+ $(
+ ${index()},
+ $( ${ignore(path)} )*
+ )*
+ ]);
+
+ #[inline]
+ fn into_usize(self) -> usize {
+ // This forbids use of repeating patterns (`Enum::V`&`Enum::V`, etc)
+ // (or at least it should, see <https://github.com/rust-lang/rust/issues/110613>)
+ #[forbid(unreachable_patterns)]
+ match self {
+ // `match` is doing heavy lifting here, by requiring exhaustiveness
+ $(
+ $($path)::* $( { $( $fields )* } )? => ${index()},
+ )*
+ }
+ }
+
+ #[inline]
+ unsafe fn from_usize(tag: usize) -> Self {
+ match tag {
+ $(
+ ${index()} => $($path)::* $( { $( $fields )* } )?,
+ )*
+
+ // Safety:
+ // `into_usize` only returns `${index()}` of the same
+ // repetition as we are filtering above, thus if this is
+ // reached, the safety contract of this function was
+ // already breached.
+ _ => unsafe {
+ debug_assert!(
+ false,
+ "invalid tag: {tag}\
+ (this is a bug in the caller of `from_usize`)"
+ );
+ std::hint::unreachable_unchecked()
+ },
+ }
+ }
+
+ }
+ };
+}
+
+#[cfg(test)]
+mod tests;
diff --git a/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs
new file mode 100644
index 000000000..62c926153
--- /dev/null
+++ b/compiler/rustc_data_structures/src/tagged_ptr/impl_tag/tests.rs
@@ -0,0 +1,34 @@
+#[test]
+fn bits_constant() {
+ use crate::tagged_ptr::Tag;
+
+ #[derive(Copy, Clone)]
+ struct Unit;
+ impl_tag! { impl Tag for Unit; Unit, }
+ assert_eq!(Unit::BITS, 0);
+
+ #[derive(Copy, Clone)]
+ enum Enum3 {
+ A,
+ B,
+ C,
+ }
+ impl_tag! { impl Tag for Enum3; Enum3::A, Enum3::B, Enum3::C, }
+ assert_eq!(Enum3::BITS, 2);
+
+ #[derive(Copy, Clone)]
+ struct Eight(bool, bool, bool);
+ impl_tag! {
+ impl Tag for Eight;
+ Eight { 0: true, 1: true, 2: true },
+ Eight { 0: true, 1: true, 2: false },
+ Eight { 0: true, 1: false, 2: true },
+ Eight { 0: true, 1: false, 2: false },
+ Eight { 0: false, 1: true, 2: true },
+ Eight { 0: false, 1: true, 2: false },
+ Eight { 0: false, 1: false, 2: true },
+ Eight { 0: false, 1: false, 2: false },
+ }
+
+ assert_eq!(Eight::BITS, 3);
+}
diff --git a/compiler/rustc_data_structures/src/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs
index ce60d40b2..fda72c9a3 100644
--- a/compiler/rustc_data_structures/src/vec_linked_list.rs
+++ b/compiler/rustc_data_structures/src/vec_linked_list.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
pub fn iter<Ls>(
first: Option<Ls::LinkIndex>,
diff --git a/compiler/rustc_data_structures/src/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs
index 10317f1af..9db6b6f20 100644
--- a/compiler/rustc_data_structures/src/work_queue.rs
+++ b/compiler/rustc_data_structures/src/work_queue.rs
@@ -1,5 +1,5 @@
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use std::collections::VecDeque;
/// A work queue is a handy data structure for tracking work left to
diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml
index 73a1f79a0..67352c55c 100644
--- a/compiler/rustc_driver_impl/Cargo.toml
+++ b/compiler/rustc_driver_impl/Cargo.toml
@@ -18,6 +18,7 @@ rustc_const_eval = { path = "../rustc_const_eval" }
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_expand = { path = "../rustc_expand" }
rustc_hir_typeck = { path = "../rustc_hir_typeck" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_incremental = { path = "../rustc_incremental" }
rustc_infer = { path = "../rustc_infer" }
rustc_mir_build = { path = "../rustc_mir_build" }
@@ -50,12 +51,13 @@ rustc_interface = { path = "../rustc_interface" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_hir_analysis = { path = "../rustc_hir_analysis" }
+rustc_mir_transform = { path = "../rustc_mir_transform" }
[target.'cfg(unix)'.dependencies]
libc = "0.2"
[target.'cfg(windows)'.dependencies.windows]
-version = "0.46.0"
+version = "0.48.0"
features = [
"Win32_System_Diagnostics_Debug",
]
@@ -63,5 +65,8 @@ features = [
[features]
llvm = ['rustc_interface/llvm']
max_level_info = ['rustc_log/max_level_info']
-rustc_use_parallel_compiler = ['rustc_data_structures/rustc_use_parallel_compiler', 'rustc_interface/rustc_use_parallel_compiler',
- 'rustc_middle/rustc_use_parallel_compiler']
+rustc_use_parallel_compiler = [
+ 'rustc_data_structures/rustc_use_parallel_compiler',
+ 'rustc_interface/rustc_use_parallel_compiler',
+ 'rustc_middle/rustc_use_parallel_compiler'
+]
diff --git a/compiler/rustc_driver_impl/messages.ftl b/compiler/rustc_driver_impl/messages.ftl
index f19b1ff64..22b4ec6b0 100644
--- a/compiler/rustc_driver_impl/messages.ftl
+++ b/compiler/rustc_driver_impl/messages.ftl
@@ -1,19 +1,19 @@
-driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
-
-driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
+driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
+driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
+driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_ice_flags = compiler flags: {$flags}
+driver_impl_ice_version = rustc {$version} running on {$triple}
driver_impl_rlink_empty_version_number = The input does not contain version number
driver_impl_rlink_encoding_version_mismatch = .rlink file was produced with encoding version `{$version_array}`, but the current version is `{$rlink_version}`
+driver_impl_rlink_no_a_file = rlink must be a file
+
driver_impl_rlink_rustc_version_mismatch = .rlink file was produced by rustc version `{$rustc_version}`, but the current version is `{$current_version}`
-driver_impl_rlink_no_a_file = rlink must be a file
+driver_impl_rlink_unable_to_read = failed to read rlink file: `{$err}`
-driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
+driver_impl_rlink_wrong_file_type = The input does not look like a .rlink file
-driver_impl_ice = the compiler unexpectedly panicked. this is a bug.
-driver_impl_ice_bug_report = we would appreciate a bug report: {$bug_report_url}
-driver_impl_ice_version = rustc {$version} running on {$triple}
-driver_impl_ice_flags = compiler flags: {$flags}
-driver_impl_ice_exclude_cargo_defaults = some of the compiler flags provided by cargo are hidden
+driver_impl_unpretty_dump_fail = pretty-print failed to write `{$path}` due to error `{$err}`
diff --git a/compiler/rustc_driver_impl/src/args.rs b/compiler/rustc_driver_impl/src/args.rs
index 42c97cc6a..eb92ccc17 100644
--- a/compiler/rustc_driver_impl/src/args.rs
+++ b/compiler/rustc_driver_impl/src/args.rs
@@ -18,6 +18,9 @@ fn arg_expand(arg: String) -> Result<Vec<String>, Error> {
}
}
+/// **Note:** This function doesn't interpret argument 0 in any special way.
+/// If this function is intended to be used with command line arguments,
+/// `argv[0]` must be removed prior to calling it manually.
pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
let mut args = Vec::new();
for arg in at_args {
@@ -25,7 +28,7 @@ pub fn arg_expand_all(at_args: &[String]) -> Vec<String> {
Ok(arg) => args.extend(arg),
Err(err) => rustc_session::early_error(
rustc_session::config::ErrorOutputType::default(),
- &format!("Failed to load argument file: {err}"),
+ format!("Failed to load argument file: {err}"),
),
}
}
diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs
index b9f0e756e..0b5d73709 100644
--- a/compiler/rustc_driver_impl/src/lib.rs
+++ b/compiler/rustc_driver_impl/src/lib.rs
@@ -25,13 +25,13 @@ use rustc_data_structures::profiling::{
use rustc_data_structures::sync::SeqCst;
use rustc_errors::registry::{InvalidErrorCode, Registry};
use rustc_errors::{
- DiagnosticMessage, ErrorGuaranteed, PResult, SubdiagnosticMessage, TerminalUrl,
+ DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage, TerminalUrl,
};
use rustc_feature::find_gated_cfg;
+use rustc_fluent_macro::fluent_messages;
use rustc_interface::util::{self, collect_crate_types, get_codegen_backend};
use rustc_interface::{interface, Queries};
use rustc_lint::LintStore;
-use rustc_macros::fluent_messages;
use rustc_metadata::locator;
use rustc_session::config::{nightly_options, CG_OPTIONS, Z_OPTIONS};
use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths};
@@ -55,11 +55,19 @@ use std::panic::{self, catch_unwind};
use std::path::PathBuf;
use std::process::{self, Command, Stdio};
use std::str;
-use std::sync::LazyLock;
+use std::sync::OnceLock;
use std::time::Instant;
+// This import blocks the use of panicking `print` and `println` in all the code
+// below. Please use `safe_print` and `safe_println` to avoid ICE when
+// encountering an I/O error during print.
+#[allow(unused_imports)]
+use std::{compile_error as print, compile_error as println};
+
pub mod args;
pub mod pretty;
+#[macro_use]
+mod print;
mod session_diagnostics;
use crate::session_diagnostics::{
@@ -91,6 +99,7 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[
rustc_middle::DEFAULT_LOCALE_RESOURCE,
rustc_mir_build::DEFAULT_LOCALE_RESOURCE,
rustc_mir_dataflow::DEFAULT_LOCALE_RESOURCE,
+ rustc_mir_transform::DEFAULT_LOCALE_RESOURCE,
rustc_monomorphize::DEFAULT_LOCALE_RESOURCE,
rustc_parse::DEFAULT_LOCALE_RESOURCE,
rustc_passes::DEFAULT_LOCALE_RESOURCE,
@@ -111,7 +120,7 @@ pub const EXIT_SUCCESS: i32 = 0;
/// Exit status code used for compilation failures and invalid flags.
pub const EXIT_FAILURE: i32 = 1;
-const BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
+pub const DEFAULT_BUG_REPORT_URL: &str = "https://github.com/rust-lang/rust/issues/new\
?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md";
const ICE_REPORT_COMPILER_FLAGS: &[&str] = &["-Z", "-C", "--crate-type"];
@@ -241,12 +250,25 @@ fn run_compiler(
Box<dyn FnOnce(&config::Options) -> Box<dyn CodegenBackend> + Send>,
>,
) -> interface::Result<()> {
+ // Throw away the first argument, the name of the binary.
+ // In case of at_args being empty, as might be the case by
+ // passing empty argument array to execve under some platforms,
+ // just use an empty slice.
+ //
+ // This situation was possible before due to arg_expand_all being
+ // called before removing the argument, enabling a crash by calling
+ // the compiler with @empty_file as argv[0] and no more arguments.
+ let at_args = at_args.get(1..).unwrap_or_default();
+
let args = args::arg_expand_all(at_args);
let Some(matches) = handle_options(&args) else { return Ok(()) };
let sopts = config::build_session_options(&matches);
+ // Set parallel mode before thread pool creation, which will create `Lock`s.
+ interface::set_thread_safe_mode(&sopts.unstable_opts);
+
if let Some(ref code) = matches.opt_str("explain") {
handle_explain(diagnostics_registry(), code, sopts.error_format);
return Ok(());
@@ -310,7 +332,7 @@ fn run_compiler(
1 => panic!("make_input should have provided valid inputs"),
_ => early_error(
config.opts.error_format,
- &format!(
+ format!(
"multiple input filenames provided (first two filenames are `{}` and `{}`)",
matches.free[0], matches.free[1],
),
@@ -511,11 +533,11 @@ fn handle_explain(registry: Registry, code: &str, output: ErrorOutputType) {
if io::stdout().is_terminal() {
show_content_with_pager(&text);
} else {
- print!("{text}");
+ safe_print!("{text}");
}
}
Err(InvalidErrorCode) => {
- early_error(output, &format!("{code} is not a valid error code"));
+ early_error(output, format!("{code} is not a valid error code"));
}
}
}
@@ -547,7 +569,7 @@ fn show_content_with_pager(content: &str) {
// If pager fails for whatever reason, we should still print the content
// to standard output
if fallback_to_println {
- print!("{content}");
+ safe_print!("{content}");
}
}
@@ -560,7 +582,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
let rlink_data = fs::read(file).unwrap_or_else(|err| {
sess.emit_fatal(RlinkUnableToRead { err });
});
- let codegen_results = match CodegenResults::deserialize_rlink(rlink_data) {
+ let codegen_results = match CodegenResults::deserialize_rlink(sess, rlink_data) {
Ok(codegen) => codegen,
Err(err) => {
match err {
@@ -574,10 +596,10 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp
rlink_version,
})
}
- CodegenErrors::RustcVersionMismatch { rustc_version, current_version } => {
+ CodegenErrors::RustcVersionMismatch { rustc_version } => {
sess.emit_fatal(RLinkRustcVersionMismatch {
rustc_version,
- current_version,
+ current_version: sess.cfg_version,
})
}
};
@@ -601,7 +623,7 @@ pub fn list_metadata(sess: &Session, metadata_loader: &dyn MetadataLoader) -> Co
let path = &(*ifile);
let mut v = Vec::new();
locator::list_file_metadata(&sess.target, path, metadata_loader, &mut v).unwrap();
- println!("{}", String::from_utf8(v).unwrap());
+ safe_println!("{}", String::from_utf8(v).unwrap());
}
Input::Str { .. } => {
early_error(ErrorOutputType::default(), "cannot list metadata for stdin");
@@ -642,12 +664,12 @@ fn print_crate_info(
TargetList => {
let mut targets = rustc_target::spec::TARGETS.to_vec();
targets.sort_unstable();
- println!("{}", targets.join("\n"));
+ safe_println!("{}", targets.join("\n"));
}
- Sysroot => println!("{}", sess.sysroot.display()),
- TargetLibdir => println!("{}", sess.target_tlib_path.dir.display()),
+ Sysroot => safe_println!("{}", sess.sysroot.display()),
+ TargetLibdir => safe_println!("{}", sess.target_tlib_path.dir.display()),
TargetSpec => {
- println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
+ safe_println!("{}", serde_json::to_string_pretty(&sess.target.to_json()).unwrap());
}
AllTargetSpecs => {
let mut targets = BTreeMap::new();
@@ -656,7 +678,7 @@ fn print_crate_info(
let target = Target::expect_builtin(&triple);
targets.insert(name, target.to_json());
}
- println!("{}", serde_json::to_string_pretty(&targets).unwrap());
+ safe_println!("{}", serde_json::to_string_pretty(&targets).unwrap());
}
FileNames | CrateName => {
let Some(attrs) = attrs.as_ref() else {
@@ -666,14 +688,14 @@ fn print_crate_info(
let t_outputs = rustc_interface::util::build_output_filenames(attrs, sess);
let id = rustc_session::output::find_crate_name(sess, attrs);
if *req == PrintRequest::CrateName {
- println!("{id}");
+ safe_println!("{id}");
continue;
}
let crate_types = collect_crate_types(sess, attrs);
for &style in &crate_types {
let fname =
rustc_session::output::filename_for_input(sess, style, id, &t_outputs);
- println!("{}", fname.file_name().unwrap().to_string_lossy());
+ safe_println!("{}", fname.file_name().unwrap().to_string_lossy());
}
}
Cfg => {
@@ -707,13 +729,13 @@ fn print_crate_info(
cfgs.sort();
for cfg in cfgs {
- println!("{cfg}");
+ safe_println!("{cfg}");
}
}
CallingConventions => {
let mut calling_conventions = rustc_target::spec::abi::all_names();
calling_conventions.sort_unstable();
- println!("{}", calling_conventions.join("\n"));
+ safe_println!("{}", calling_conventions.join("\n"));
}
RelocationModels
| CodeModels
@@ -733,10 +755,26 @@ fn print_crate_info(
let stable = sess.target.options.supported_split_debuginfo.contains(split);
let unstable_ok = sess.unstable_options();
if stable || unstable_ok {
- println!("{split}");
+ safe_println!("{split}");
}
}
}
+ DeploymentTarget => {
+ use rustc_target::spec::current_apple_deployment_target;
+
+ if sess.target.is_like_osx {
+ safe_println!(
+ "deployment_target={}",
+ current_apple_deployment_target(&sess.target)
+ .expect("unknown Apple target OS")
+ )
+ } else {
+ early_error(
+ ErrorOutputType::default(),
+ "only Apple targets currently support deployment version info",
+ )
+ }
+ }
}
}
Compilation::Stop
@@ -770,14 +808,14 @@ pub fn version_at_macro_invocation(
) {
let verbose = matches.opt_present("verbose");
- println!("{binary} {version}");
+ safe_println!("{binary} {version}");
if verbose {
- println!("binary: {binary}");
- println!("commit-hash: {commit_hash}");
- println!("commit-date: {commit_date}");
- println!("host: {}", config::host_triple());
- println!("release: {release}");
+ safe_println!("binary: {binary}");
+ safe_println!("commit-hash: {commit_hash}");
+ safe_println!("commit-date: {commit_date}");
+ safe_println!("host: {}", config::host_triple());
+ safe_println!("release: {release}");
let debug_flags = matches.opt_strs("Z");
let backend_name = debug_flags.iter().find_map(|x| x.strip_prefix("codegen-backend="));
@@ -807,7 +845,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
} else {
""
};
- println!(
+ safe_println!(
"{options}{at_path}\nAdditional help:
-C help Print codegen options
-W help \
@@ -820,7 +858,7 @@ fn usage(verbose: bool, include_unstable_options: bool, nightly_build: bool) {
}
fn print_wall_help() {
- println!(
+ safe_println!(
"
The flag `-Wall` does not exist in `rustc`. Most useful lints are enabled by
default. Use `rustc -W help` to see all available lints. It's more common to put
@@ -832,7 +870,7 @@ the command line flag directly.
/// Write to stdout lint command options, together with a list of all available lints
pub fn describe_lints(sess: &Session, lint_store: &LintStore, loaded_plugins: bool) {
- println!(
+ safe_println!(
"
Available lint options:
-W <foo> Warn about <foo>
@@ -877,21 +915,21 @@ Available lint options:
s
};
- println!("Lint checks provided by rustc:\n");
+ safe_println!("Lint checks provided by rustc:\n");
let print_lints = |lints: Vec<&Lint>| {
- println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
- println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
+ safe_println!(" {} {:7.7} {}", padded("name"), "default", "meaning");
+ safe_println!(" {} {:7.7} {}", padded("----"), "-------", "-------");
for lint in lints {
let name = lint.name_lower().replace('_', "-");
- println!(
+ safe_println!(
" {} {:7.7} {}",
padded(&name),
lint.default_level(sess.edition()).as_str(),
lint.desc
);
}
- println!("\n");
+ safe_println!("\n");
};
print_lints(builtin);
@@ -912,14 +950,14 @@ Available lint options:
s
};
- println!("Lint groups provided by rustc:\n");
+ safe_println!("Lint groups provided by rustc:\n");
let print_lint_groups = |lints: Vec<(&'static str, Vec<LintId>)>, all_warnings| {
- println!(" {} sub-lints", padded("name"));
- println!(" {} ---------", padded("----"));
+ safe_println!(" {} sub-lints", padded("name"));
+ safe_println!(" {} ---------", padded("----"));
if all_warnings {
- println!(" {} all lints that are set to issue warnings", padded("warnings"));
+ safe_println!(" {} all lints that are set to issue warnings", padded("warnings"));
}
for (name, to) in lints {
@@ -929,26 +967,26 @@ Available lint options:
.map(|x| x.to_string().replace('_', "-"))
.collect::<Vec<String>>()
.join(", ");
- println!(" {} {}", padded(&name), desc);
+ safe_println!(" {} {}", padded(&name), desc);
}
- println!("\n");
+ safe_println!("\n");
};
print_lint_groups(builtin_groups, true);
match (loaded_plugins, plugin.len(), plugin_groups.len()) {
(false, 0, _) | (false, _, 0) => {
- println!("Lint tools like Clippy can provide additional lints and lint groups.");
+ safe_println!("Lint tools like Clippy can provide additional lints and lint groups.");
}
(false, ..) => panic!("didn't load lint plugins but got them anyway!"),
- (true, 0, 0) => println!("This crate does not load any lint plugins or lint groups."),
+ (true, 0, 0) => safe_println!("This crate does not load any lint plugins or lint groups."),
(true, l, g) => {
if l > 0 {
- println!("Lint checks provided by plugins loaded by this crate:\n");
+ safe_println!("Lint checks provided by plugins loaded by this crate:\n");
print_lints(plugin);
}
if g > 0 {
- println!("Lint groups provided by plugins loaded by this crate:\n");
+ safe_println!("Lint groups provided by plugins loaded by this crate:\n");
print_lint_groups(plugin_groups, false);
}
}
@@ -996,12 +1034,12 @@ pub fn describe_flag_categories(matches: &Matches) -> bool {
}
fn describe_debug_flags() {
- println!("\nAvailable options:\n");
+ safe_println!("\nAvailable options:\n");
print_flag_list("-Z", config::Z_OPTIONS);
}
fn describe_codegen_flags() {
- println!("\nAvailable codegen options:\n");
+ safe_println!("\nAvailable codegen options:\n");
print_flag_list("-C", config::CG_OPTIONS);
}
@@ -1012,7 +1050,7 @@ fn print_flag_list<T>(
let max_len = flag_list.iter().map(|&(name, _, _, _)| name.chars().count()).max().unwrap_or(0);
for &(name, _, _, desc) in flag_list {
- println!(
+ safe_println!(
" {} {:>width$}=val -- {}",
cmdline_opt,
name.replace('_', "-"),
@@ -1046,9 +1084,6 @@ fn print_flag_list<T>(
/// So with all that in mind, the comments below have some more detail about the
/// contortions done here to get things to work out correctly.
pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
- // Throw away the first argument, the name of the binary
- let args = &args[1..];
-
if args.is_empty() {
// user did not write `-v` nor `-Z unstable-options`, so do not
// include that extra information.
@@ -1074,7 +1109,7 @@ pub fn handle_options(args: &[String]) -> Option<getopts::Matches> {
.map(|(flag, _)| format!("{e}. Did you mean `-{flag} {opt}`?")),
_ => None,
};
- early_error(ErrorOutputType::default(), &msg.unwrap_or_else(|| e.to_string()));
+ early_error(ErrorOutputType::default(), msg.unwrap_or_else(|| e.to_string()));
});
// For all options we just parsed, we check a few aspects:
@@ -1170,6 +1205,7 @@ fn extra_compiler_flags() -> Option<(Vec<String>, bool)> {
pub fn catch_fatal_errors<F: FnOnce() -> R, R>(f: F) -> Result<R, ErrorGuaranteed> {
catch_unwind(panic::AssertUnwindSafe(f)).map_err(|value| {
if value.is::<rustc_errors::FatalErrorMarker>() {
+ #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
} else {
panic::resume_unwind(value);
@@ -1187,35 +1223,59 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 {
}
}
-static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
- LazyLock::new(|| {
- let hook = panic::take_hook();
- panic::set_hook(Box::new(|info| {
- // If the error was caused by a broken pipe then this is not a bug.
- // Write the error and return immediately. See #98700.
- #[cfg(windows)]
- if let Some(msg) = info.payload().downcast_ref::<String>() {
- if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)")
- {
- early_error_no_abort(ErrorOutputType::default(), &msg);
- return;
- }
- };
+/// Stores the default panic hook, from before [`install_ice_hook`] was called.
+static DEFAULT_HOOK: OnceLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send + 'static>> =
+ OnceLock::new();
+
+/// Installs a panic hook that will print the ICE message on unexpected panics.
+///
+/// The hook is intended to be useable even by external tools. You can pass a custom
+/// `bug_report_url`, or report arbitrary info in `extra_info`. Note that `extra_info` is called in
+/// a context where *the thread is currently panicking*, so it must not panic or the process will
+/// abort.
+///
+/// If you have no extra info to report, pass the empty closure `|_| ()` as the argument to
+/// extra_info.
+///
+/// A custom rustc driver can skip calling this to set up a custom ICE hook.
+pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) {
+ // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
+ // full backtraces. When a compiler ICE happens, we want to gather
+ // as much information as possible to present in the issue opened
+ // by the user. Compiler developers and other rustc users can
+ // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
+ // (e.g. `RUST_BACKTRACE=1`)
+ if std::env::var("RUST_BACKTRACE").is_err() {
+ std::env::set_var("RUST_BACKTRACE", "full");
+ }
- // Invoke the default handler, which prints the actual panic message and optionally a backtrace
- // Don't do this for delayed bugs, which already emit their own more useful backtrace.
- if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
- (*DEFAULT_HOOK)(info);
+ let default_hook = DEFAULT_HOOK.get_or_init(panic::take_hook);
- // Separate the output with an empty line
- eprintln!();
+ panic::set_hook(Box::new(move |info| {
+ // If the error was caused by a broken pipe then this is not a bug.
+ // Write the error and return immediately. See #98700.
+ #[cfg(windows)]
+ if let Some(msg) = info.payload().downcast_ref::<String>() {
+ if msg.starts_with("failed printing to stdout: ") && msg.ends_with("(os error 232)") {
+ // the error code is already going to be reported when the panic unwinds up the stack
+ let _ = early_error_no_abort(ErrorOutputType::default(), msg.as_str());
+ return;
}
+ };
- // Print the ICE message
- report_ice(info, BUG_REPORT_URL);
- }));
- hook
- });
+ // Invoke the default handler, which prints the actual panic message and optionally a backtrace
+ // Don't do this for delayed bugs, which already emit their own more useful backtrace.
+ if !info.payload().is::<rustc_errors::DelayedBugPanic>() {
+ (*default_hook)(info);
+
+ // Separate the output with an empty line
+ eprintln!();
+ }
+
+ // Print the ICE message
+ report_ice(info, bug_report_url, extra_info);
+ }));
+}
/// Prints the ICE message, including query stack, but without backtrace.
///
@@ -1223,7 +1283,7 @@ static DEFAULT_HOOK: LazyLock<Box<dyn Fn(&panic::PanicInfo<'_>) + Sync + Send +
///
/// When `install_ice_hook` is called, this function will be called as the panic
/// hook.
-pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
+pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) {
let fallback_bundle =
rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false);
let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr(
@@ -1262,12 +1322,16 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
// If backtraces are enabled, also print the query stack
- let backtrace = env::var_os("RUST_BACKTRACE").map_or(false, |x| &x != "0");
+ let backtrace = env::var_os("RUST_BACKTRACE").is_some_and(|x| &x != "0");
let num_frames = if backtrace { None } else { Some(2) };
interface::try_print_query_stack(&handler, num_frames);
+ // We don't trust this callback not to panic itself, so run it at the end after we're sure we've
+ // printed all the relevant info.
+ extra_info(&handler);
+
#[cfg(windows)]
if env::var("RUSTC_BREAK_ON_ICE").is_ok() {
// Trigger a debugger if we crashed during bootstrap
@@ -1275,22 +1339,6 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) {
}
}
-/// Installs a panic hook that will print the ICE message on unexpected panics.
-///
-/// A custom rustc driver can skip calling this to set up a custom ICE hook.
-pub fn install_ice_hook() {
- // If the user has not explicitly overridden "RUST_BACKTRACE", then produce
- // full backtraces. When a compiler ICE happens, we want to gather
- // as much information as possible to present in the issue opened
- // by the user. Compiler developers and other rustc users can
- // opt in to less-verbose backtraces by manually setting "RUST_BACKTRACE"
- // (e.g. `RUST_BACKTRACE=1`)
- if std::env::var("RUST_BACKTRACE").is_err() {
- std::env::set_var("RUST_BACKTRACE", "full");
- }
- LazyLock::force(&DEFAULT_HOOK);
-}
-
/// This allows tools to enable rust logging without having to magically match rustc's
/// tracing crate version.
pub fn init_rustc_env_logger() {
@@ -1302,7 +1350,7 @@ pub fn init_rustc_env_logger() {
/// other than `RUSTC_LOG`.
pub fn init_env_logger(env: &str) {
if let Err(error) = rustc_log::init_env_logger(env) {
- early_error(ErrorOutputType::default(), &error.to_string());
+ early_error(ErrorOutputType::default(), error.to_string());
}
}
@@ -1361,7 +1409,7 @@ pub fn main() -> ! {
init_rustc_env_logger();
signal_handler::install();
let mut callbacks = TimePassesCallbacks::default();
- install_ice_hook();
+ install_ice_hook(DEFAULT_BUG_REPORT_URL, |_| ());
let exit_code = catch_with_exit_code(|| {
let args = env::args_os()
.enumerate()
@@ -1369,7 +1417,7 @@ pub fn main() -> ! {
arg.into_string().unwrap_or_else(|arg| {
early_error(
ErrorOutputType::default(),
- &format!("argument {i} is not valid Unicode: {arg:?}"),
+ format!("argument {i} is not valid Unicode: {arg:?}"),
)
})
})
diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs
index 446c6832c..ee64b18d3 100644
--- a/compiler/rustc_driver_impl/src/pretty.rs
+++ b/compiler/rustc_driver_impl/src/pretty.rs
@@ -488,12 +488,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR tree");
for did in tcx.hir().body_owners() {
- let _ = writeln!(
- out,
- "{:?}:\n{}\n",
- did,
- tcx.thir_tree(ty::WithOptConstParam::unknown(did))
- );
+ let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_tree(did));
}
out
}
@@ -503,12 +498,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante
abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess);
debug!("pretty printing THIR flat");
for did in tcx.hir().body_owners() {
- let _ = writeln!(
- out,
- "{:?}:\n{}\n",
- did,
- tcx.thir_flat(ty::WithOptConstParam::unknown(did))
- );
+ let _ = writeln!(out, "{:?}:\n{}\n", did, tcx.thir_flat(did));
}
out
}
diff --git a/compiler/rustc_driver_impl/src/print.rs b/compiler/rustc_driver_impl/src/print.rs
new file mode 100644
index 000000000..70de55320
--- /dev/null
+++ b/compiler/rustc_driver_impl/src/print.rs
@@ -0,0 +1,20 @@
+use std::fmt;
+use std::io::{self, Write as _};
+
+macro_rules! safe_print {
+ ($($arg:tt)*) => {{
+ $crate::print::print(std::format_args!($($arg)*));
+ }};
+}
+
+macro_rules! safe_println {
+ ($($arg:tt)*) => {
+ safe_print!("{}\n", std::format_args!($($arg)*))
+ };
+}
+
+pub(crate) fn print(args: fmt::Arguments<'_>) {
+ if let Err(_) = io::stdout().write_fmt(args) {
+ rustc_errors::FatalError.raise();
+ }
+}
diff --git a/compiler/rustc_error_codes/src/error_codes/E0026.md b/compiler/rustc_error_codes/src/error_codes/E0026.md
index 72c575aab..f485112cc 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0026.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0026.md
@@ -1,4 +1,4 @@
-A struct pattern attempted to extract a non-existent field from a struct.
+A struct pattern attempted to extract a nonexistent field from a struct.
Erroneous code example:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0208.md b/compiler/rustc_error_codes/src/error_codes/E0208.md
index 1ae01106f..c6db9b5d6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0208.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0208.md
@@ -32,7 +32,7 @@ error: [-, o]
This error is deliberately triggered with the `#[rustc_variance]` attribute
(`#![feature(rustc_attrs)]` must be enabled) and helps to show you the variance
of the type's generic parameters. You can read more about variance and
-subtyping in [this section of the Rustnomicon]. For a more in depth look at
+subtyping in [this section of the Rustonomicon]. For a more in depth look at
variance (including a more complete list of common variances) see
[this section of the Reference]. For information on how variance is implemented
in the compiler, see [this section of `rustc-dev-guide`].
@@ -41,6 +41,6 @@ This error can be easily fixed by removing the `#[rustc_variance]` attribute,
the compiler's suggestion to comment it out can be applied automatically with
`rustfix`.
-[this section of the Rustnomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
+[this section of the Rustonomicon]: https://doc.rust-lang.org/nomicon/subtyping.html
[this section of the Reference]: https://doc.rust-lang.org/reference/subtyping.html#variance
[this section of `rustc-dev-guide`]: https://rustc-dev-guide.rust-lang.org/variance.html
diff --git a/compiler/rustc_error_codes/src/error_codes/E0311.md b/compiler/rustc_error_codes/src/error_codes/E0311.md
index 08159d3f4..c1104a88a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0311.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0311.md
@@ -29,7 +29,7 @@ If `no_restriction()` were to use `&T` instead of `&()` as an argument, the
compiler would have added an implied bound, causing this to compile.
This error can be resolved by explicitly naming the elided lifetime for `x` and
-then explicily requiring that the generic parameter `T` outlives that lifetime:
+then explicitly requiring that the generic parameter `T` outlives that lifetime:
```
fn no_restriction<'a, T: 'a>(x: &'a ()) -> &'a () {
diff --git a/compiler/rustc_error_codes/src/error_codes/E0457.md b/compiler/rustc_error_codes/src/error_codes/E0457.md
index 53d384d36..2c33d1e6a 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0457.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0457.md
@@ -1,6 +1,6 @@
Plugin `..` only found in rlib format, but must be available in dylib format.
-Erroronous code example:
+Erroneous code example:
`rlib-plugin.rs`
```ignore (needs-linkage-with-other-tests)
diff --git a/compiler/rustc_error_codes/src/error_codes/E0576.md b/compiler/rustc_error_codes/src/error_codes/E0576.md
index 8eead4e7e..300a57a19 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0576.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0576.md
@@ -10,7 +10,7 @@ trait Hello {
}
```
-In this example, we tried to use the non-existent associated type `You` of the
+In this example, we tried to use the nonexistent associated type `You` of the
`Hello` trait. To fix this error, use an existing associated type:
```
diff --git a/compiler/rustc_error_codes/src/error_codes/E0609.md b/compiler/rustc_error_codes/src/error_codes/E0609.md
index a9db34f47..0f5ac94e6 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0609.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0609.md
@@ -1,4 +1,4 @@
-Attempted to access a non-existent field in a struct.
+Attempted to access a nonexistent field in a struct.
Erroneous code example:
diff --git a/compiler/rustc_error_codes/src/error_codes/E0726.md b/compiler/rustc_error_codes/src/error_codes/E0726.md
index e3794327f..a721e746e 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0726.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0726.md
@@ -25,8 +25,8 @@ block_on(future);
Specify desired lifetime of parameter `content` or indicate the anonymous
lifetime like `content: Content<'_>`. The anonymous lifetime tells the Rust
-compiler that `content` is only needed until create function is done with
-it's execution.
+compiler that `content` is only needed until the `create` function is done with
+its execution.
The `implicit elision` meaning the omission of suggested lifetime that is
`pub async fn create<'a>(content: Content<'a>) {}` is not allowed here as
diff --git a/compiler/rustc_error_codes/src/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md
index a2a1a20f2..4f3659002 100644
--- a/compiler/rustc_error_codes/src/error_codes/E0771.md
+++ b/compiler/rustc_error_codes/src/error_codes/E0771.md
@@ -1,9 +1,11 @@
+#### Note: this error code is no longer emitted by the compiler
+
A non-`'static` lifetime was used in a const generic. This is currently not
allowed.
Erroneous code example:
-```compile_fail,E0771
+```compile_fail,E0770
#![feature(adt_const_params)]
fn function_with_str<'a, const STRING: &'a str>() {} // error!
diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml
index 27783d60b..4df5a8d48 100644
--- a/compiler/rustc_error_messages/Cargo.toml
+++ b/compiler/rustc_error_messages/Cargo.toml
@@ -11,14 +11,15 @@ fluent-syntax = "0.11"
intl-memoizer = "0.5.1"
rustc_baked_icu_data = { path = "../rustc_baked_icu_data" }
rustc_data_structures = { path = "../rustc_data_structures" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
tracing = "0.1"
unic-langid = { version = "0.9.0", features = ["macros"] }
-icu_list = "1.1.0"
-icu_locid = "1.1.0"
-icu_provider_adapters = "1.1.0"
+icu_list = "1.2"
+icu_locid = "1.2"
+icu_provider_adapters = "1.2"
[features]
rustc_use_parallel_compiler = ['rustc_baked_icu_data/rustc_use_parallel_compiler']
diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs
index 6f319b96f..0accb4ab9 100644
--- a/compiler/rustc_error_messages/src/lib.rs
+++ b/compiler/rustc_error_messages/src/lib.rs
@@ -11,8 +11,9 @@ extern crate tracing;
use fluent_bundle::FluentResource;
use fluent_syntax::parser::ParserError;
use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker};
-use rustc_data_structures::sync::Lrc;
-use rustc_macros::{fluent_messages, Decodable, Encodable};
+use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
+use rustc_fluent_macro::fluent_messages;
+use rustc_macros::{Decodable, Encodable};
use rustc_span::Span;
use std::borrow::Cow;
use std::error::Error;
@@ -36,16 +37,17 @@ pub use unic_langid::{langid, LanguageIdentifier};
fluent_messages! { "../messages.ftl" }
-pub type FluentBundle = fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>;
+pub type FluentBundle =
+ IntoDynSyncSend<fluent_bundle::bundle::FluentBundle<FluentResource, IntlLangMemoizer>>;
-#[cfg(parallel_compiler)]
+#[cfg(not(parallel_compiler))]
fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
- FluentBundle::new_concurrent(locales)
+ IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new(locales))
}
-#[cfg(not(parallel_compiler))]
+#[cfg(parallel_compiler)]
fn new_bundle(locales: Vec<LanguageIdentifier>) -> FluentBundle {
- FluentBundle::new(locales)
+ IntoDynSyncSend(fluent_bundle::bundle::FluentBundle::new_concurrent(locales))
}
#[derive(Debug)]
@@ -286,11 +288,19 @@ pub enum SubdiagnosticMessage {
FluentAttr(FluentId),
}
-/// `From` impl that enables existing diagnostic calls to functions which now take
-/// `impl Into<SubdiagnosticMessage>` to continue to work as before.
-impl<S: Into<String>> From<S> for SubdiagnosticMessage {
- fn from(s: S) -> Self {
- SubdiagnosticMessage::Str(s.into())
+impl From<String> for SubdiagnosticMessage {
+ fn from(s: String) -> Self {
+ SubdiagnosticMessage::Str(s)
+ }
+}
+impl<'a> From<&'a str> for SubdiagnosticMessage {
+ fn from(s: &'a str) -> Self {
+ SubdiagnosticMessage::Str(s.to_string())
+ }
+}
+impl From<Cow<'static, str>> for SubdiagnosticMessage {
+ fn from(s: Cow<'static, str>) -> Self {
+ SubdiagnosticMessage::Str(s.to_string())
}
}
@@ -351,11 +361,19 @@ impl DiagnosticMessage {
}
}
-/// `From` impl that enables existing diagnostic calls to functions which now take
-/// `impl Into<DiagnosticMessage>` to continue to work as before.
-impl<S: Into<String>> From<S> for DiagnosticMessage {
- fn from(s: S) -> Self {
- DiagnosticMessage::Str(s.into())
+impl From<String> for DiagnosticMessage {
+ fn from(s: String) -> Self {
+ DiagnosticMessage::Str(s)
+ }
+}
+impl<'a> From<&'a str> for DiagnosticMessage {
+ fn from(s: &'a str) -> Self {
+ DiagnosticMessage::Str(s.to_string())
+ }
+}
+impl From<Cow<'static, str>> for DiagnosticMessage {
+ fn from(s: Cow<'static, str>) -> Self {
+ DiagnosticMessage::Str(s.to_string())
}
}
diff --git a/compiler/rustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml
index e1ead08ea..bd3033fcb 100644
--- a/compiler/rustc_errors/Cargo.toml
+++ b/compiler/rustc_errors/Cargo.toml
@@ -10,6 +10,7 @@ tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_error_messages = { path = "../rustc_error_messages" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
rustc_macros = { path = "../rustc_macros" }
@@ -26,12 +27,11 @@ serde = { version = "1.0.125", features = [ "derive" ] }
serde_json = "1.0.59"
[target.'cfg(windows)'.dependencies.windows]
-version = "0.46.0"
+version = "0.48.0"
features = [
"Win32_Foundation",
"Win32_Security",
"Win32_System_Threading",
- "Win32_System_WindowsProgramming",
]
[features]
diff --git a/compiler/rustc_errors/messages.ftl b/compiler/rustc_errors/messages.ftl
index dde1d6c0a..337097343 100644
--- a/compiler/rustc_errors/messages.ftl
+++ b/compiler/rustc_errors/messages.ftl
@@ -1,19 +1,19 @@
-errors_target_invalid_address_space =
- invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
+errors_target_inconsistent_architecture =
+ inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
-errors_target_invalid_bits =
- invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
+errors_target_inconsistent_pointer_width =
+ inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
-errors_target_missing_alignment =
- missing alignment for `{$cause}` in "data-layout"
+errors_target_invalid_address_space =
+ invalid address space `{$addr_space}` for `{$cause}` in "data-layout": {$err}
errors_target_invalid_alignment =
invalid alignment for `{$cause}` in "data-layout": {$err}
-errors_target_inconsistent_architecture =
- inconsistent target specification: "data-layout" claims architecture is {$dl}-endian, while "target-endian" is `{$target}`
-
-errors_target_inconsistent_pointer_width =
- inconsistent target specification: "data-layout" claims pointers are {$pointer_size}-bit, while "target-pointer-width" is `{$target}`
+errors_target_invalid_bits =
+ invalid {$kind} `{$bit}` for `{$cause}` in "data-layout": {$err}
errors_target_invalid_bits_size = {$err}
+
+errors_target_missing_alignment =
+ missing alignment for `{$cause}` in "data-layout"
diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs
index 3064d2bed..db97d96fc 100644
--- a/compiler/rustc_errors/src/diagnostic_builder.rs
+++ b/compiler/rustc_errors/src/diagnostic_builder.rs
@@ -192,6 +192,7 @@ impl EmissionGuarantee for ErrorGuaranteed {
became non-error ({:?}), after original `.emit()`",
db.inner.diagnostic.level,
);
+ #[allow(deprecated)]
ErrorGuaranteed::unchecked_claim_error_was_emitted()
}
}
@@ -570,6 +571,14 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> {
Some((diagnostic, handler))
}
+ /// Retrieves the [`Handler`] if available
+ pub fn handler(&self) -> Option<&Handler> {
+ match self.inner.state {
+ DiagnosticBuilderState::Emittable(handler) => Some(handler),
+ DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => None,
+ }
+ }
+
/// Buffers the diagnostic for later emission,
/// unless handler has disabled such buffering.
pub fn buffer(self, buffered_diagnostics: &mut Vec<Diagnostic>) {
@@ -791,7 +800,7 @@ macro_rules! struct_span_err {
($session:expr, $span:expr, $code:ident, $($message:tt)*) => ({
$session.struct_span_err_with_code(
$span,
- &format!($($message)*),
+ format!($($message)*),
$crate::error_code!($code),
)
})
diff --git a/compiler/rustc_errors/src/emitter.rs b/compiler/rustc_errors/src/emitter.rs
index fe44799ef..e8cd7eaa6 100644
--- a/compiler/rustc_errors/src/emitter.rs
+++ b/compiler/rustc_errors/src/emitter.rs
@@ -285,15 +285,11 @@ pub trait Emitter: Translate {
format!(
"help: {}{}: `{}`",
&msg,
- if self
- .source_map()
- .map(|sm| is_case_difference(
- sm,
- substitution,
- sugg.substitutions[0].parts[0].span,
- ))
- .unwrap_or(false)
- {
+ if self.source_map().is_some_and(|sm| is_case_difference(
+ sm,
+ substitution,
+ sugg.substitutions[0].parts[0].span,
+ )) {
" (notice the capitalization)"
} else {
""
@@ -336,7 +332,7 @@ pub trait Emitter: Translate {
// Skip past non-macro entries, just in case there
// are some which do actually involve macros.
- ExpnKind::Inlined | ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
+ ExpnKind::Desugaring(..) | ExpnKind::AstPass(..) => None,
ExpnKind::Macro(macro_kind, name) => Some((macro_kind, name)),
}
@@ -407,7 +403,7 @@ pub trait Emitter: Translate {
continue;
}
- if always_backtrace && !matches!(trace.kind, ExpnKind::Inlined) {
+ if always_backtrace {
new_labels.push((
trace.def_site,
format!(
@@ -446,7 +442,6 @@ pub trait Emitter: Translate {
"this derive macro expansion".into()
}
ExpnKind::Macro(MacroKind::Bang, _) => "this macro invocation".into(),
- ExpnKind::Inlined => "this inlined function call".into(),
ExpnKind::Root => "the crate root".into(),
ExpnKind::AstPass(kind) => kind.descr().into(),
ExpnKind::Desugaring(kind) => {
@@ -601,7 +596,7 @@ impl Emitter for SilentEmitter {
if d.level == Level::Fatal {
let mut d = d.clone();
if let Some(ref note) = self.fatal_note {
- d.note(note);
+ d.note(note.clone());
}
self.fatal_handler.emit_diagnostic(&mut d);
}
@@ -1336,6 +1331,7 @@ impl EmitterWriter {
// see?
for (text, style) in msg.iter() {
let text = self.translate_message(text, args).map_err(Report::new).unwrap();
+ let text = &normalize_whitespace(&text);
let lines = text.split('\n').collect::<Vec<_>>();
if lines.len() > 1 {
for (i, line) in lines.iter().enumerate() {
@@ -1980,7 +1976,7 @@ impl EmitterWriter {
}
if let DisplaySuggestion::Add = show_code_change && is_item_attribute {
// The suggestion adds an entire line of code, ending on a newline, so we'll also
- // print the *following* line, to provide context of what we're advicing people to
+ // print the *following* line, to provide context of what we're advising people to
// do. Otherwise you would only see contextless code that can be confused for
// already existing code, despite the colors and UI elements.
// We special case `#[derive(_)]\n` and other attribute suggestions, because those
@@ -2302,22 +2298,25 @@ impl EmitterWriter {
// Colorize addition/replacements with green.
for &SubstitutionHighlight { start, end } in highlight_parts {
- // Account for tabs when highlighting (#87972).
- let tabs: usize = line_to_add
- .chars()
- .take(start)
- .map(|ch| match ch {
- '\t' => 3,
- _ => 0,
- })
- .sum();
- buffer.set_style_range(
- *row_num,
- max_line_num_len + 3 + start + tabs,
- max_line_num_len + 3 + end + tabs,
- Style::Addition,
- true,
- );
+ // This is a no-op for empty ranges
+ if start != end {
+ // Account for tabs when highlighting (#87972).
+ let tabs: usize = line_to_add
+ .chars()
+ .take(start)
+ .map(|ch| match ch {
+ '\t' => 3,
+ _ => 0,
+ })
+ .sum();
+ buffer.set_style_range(
+ *row_num,
+ max_line_num_len + 3 + start + tabs,
+ max_line_num_len + 3 + end + tabs,
+ Style::Addition,
+ true,
+ );
+ }
}
*row_num += 1;
}
diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs
index d20b16890..3dec0d929 100644
--- a/compiler/rustc_errors/src/lib.rs
+++ b/compiler/rustc_errors/src/lib.rs
@@ -31,15 +31,15 @@ use Level::*;
use emitter::{is_case_difference, Emitter, EmitterWriter};
use registry::Registry;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet};
-use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{self, Lock, Lrc};
+use rustc_data_structures::stable_hasher::{Hash128, StableHasher};
+use rustc_data_structures::sync::{self, IntoDynSyncSend, Lock, Lrc};
use rustc_data_structures::AtomicRef;
pub use rustc_error_messages::{
fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle,
LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage,
};
+use rustc_fluent_macro::fluent_messages;
pub use rustc_lint_defs::{pluralize, Applicability};
-use rustc_macros::fluent_messages;
use rustc_span::source_map::SourceMap;
pub use rustc_span::ErrorGuaranteed;
use rustc_span::{Loc, Span};
@@ -330,12 +330,11 @@ impl CodeSuggestion {
});
buf.push_str(&part.snippet);
let cur_hi = sm.lookup_char_pos(part.span.hi());
- if cur_hi.line == cur_lo.line && !part.snippet.is_empty() {
- // Account for the difference between the width of the current code and the
- // snippet being suggested, so that the *later* suggestions are correctly
- // aligned on the screen.
- acc += len - (cur_hi.col.0 - cur_lo.col.0) as isize;
- }
+ // Account for the difference between the width of the current code and the
+ // snippet being suggested, so that the *later* suggestions are correctly
+ // aligned on the screen. Note that cur_hi and cur_lo can be on different
+ // lines, so cur_hi.col can be smaller than cur_lo.col
+ acc += len - (cur_hi.col.0 as isize - cur_lo.col.0 as isize);
prev_hi = cur_hi;
prev_line = sf.get_line(prev_hi.line - 1);
for line in part.snippet.split('\n').skip(1) {
@@ -409,7 +408,7 @@ struct HandlerInner {
err_count: usize,
warn_count: usize,
deduplicated_err_count: usize,
- emitter: Box<dyn Emitter + sync::Send>,
+ emitter: IntoDynSyncSend<Box<dyn Emitter + sync::Send>>,
delayed_span_bugs: Vec<DelayedDiagnostic>,
delayed_good_path_bugs: Vec<DelayedDiagnostic>,
/// This flag indicates that an expected diagnostic was emitted and suppressed.
@@ -427,7 +426,7 @@ struct HandlerInner {
/// This set contains a hash of every diagnostic that has been emitted by
/// this handler. These hashes is used to avoid emitting the same error
/// twice.
- emitted_diagnostics: FxHashSet<u128>,
+ emitted_diagnostics: FxHashSet<Hash128>,
/// Stashed diagnostics emitted in one stage of the compiler that may be
/// stolen by other stages (e.g. to improve them and add more information).
@@ -478,6 +477,8 @@ pub enum StashKey {
/// FRU syntax
MaybeFruTypo,
CallAssocMethod,
+ TraitMissingMethod,
+ OpaqueHiddenTypeMismatch,
}
fn default_track_diagnostic(d: &mut Diagnostic, f: &mut dyn FnMut(&mut Diagnostic)) {
@@ -605,7 +606,7 @@ impl Handler {
warn_count: 0,
deduplicated_err_count: 0,
deduplicated_warn_count: 0,
- emitter,
+ emitter: IntoDynSyncSend(emitter),
delayed_span_bugs: Vec::new(),
delayed_good_path_bugs: Vec::new(),
suppressed_expected_diag: false,
@@ -1069,26 +1070,29 @@ impl Handler {
}
pub fn has_errors(&self) -> Option<ErrorGuaranteed> {
- self.inner.borrow().has_errors().then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+ self.inner.borrow().has_errors().then(|| {
+ #[allow(deprecated)]
+ ErrorGuaranteed::unchecked_claim_error_was_emitted()
+ })
}
pub fn has_errors_or_lint_errors(&self) -> Option<ErrorGuaranteed> {
- self.inner
- .borrow()
- .has_errors_or_lint_errors()
- .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+ self.inner.borrow().has_errors_or_lint_errors().then(|| {
+ #[allow(deprecated)]
+ ErrorGuaranteed::unchecked_claim_error_was_emitted()
+ })
}
pub fn has_errors_or_delayed_span_bugs(&self) -> Option<ErrorGuaranteed> {
- self.inner
- .borrow()
- .has_errors_or_delayed_span_bugs()
- .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+ self.inner.borrow().has_errors_or_delayed_span_bugs().then(|| {
+ #[allow(deprecated)]
+ ErrorGuaranteed::unchecked_claim_error_was_emitted()
+ })
}
pub fn is_compilation_going_to_fail(&self) -> Option<ErrorGuaranteed> {
- self.inner
- .borrow()
- .is_compilation_going_to_fail()
- .then(ErrorGuaranteed::unchecked_claim_error_was_emitted)
+ self.inner.borrow().is_compilation_going_to_fail().then(|| {
+ #[allow(deprecated)]
+ ErrorGuaranteed::unchecked_claim_error_was_emitted()
+ })
}
pub fn print_error_count(&self, registry: &Registry) {
@@ -1333,6 +1337,7 @@ impl HandlerInner {
.push(DelayedDiagnostic::with_backtrace(diagnostic.clone(), backtrace));
if !self.flags.report_delayed_bugs {
+ #[allow(deprecated)]
return Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
}
}
@@ -1411,7 +1416,10 @@ impl HandlerInner {
self.bump_err_count();
}
- guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+ #[allow(deprecated)]
+ {
+ guaranteed = Some(ErrorGuaranteed::unchecked_claim_error_was_emitted());
+ }
} else {
self.bump_warn_count();
}
@@ -1429,7 +1437,7 @@ impl HandlerInner {
}
fn treat_err_as_bug(&self) -> bool {
- self.flags.treat_err_as_bug.map_or(false, |c| {
+ self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() >= c.get()
})
}
@@ -1462,10 +1470,10 @@ impl HandlerInner {
DiagnosticMessage::Str(warnings),
)),
(_, 0) => {
- let _ = self.fatal(&errors);
+ let _ = self.fatal(errors);
}
(_, _) => {
- let _ = self.fatal(&format!("{}; {}", &errors, &warnings));
+ let _ = self.fatal(format!("{}; {}", &errors, &warnings));
}
}
@@ -1486,18 +1494,18 @@ impl HandlerInner {
error_codes.sort();
if error_codes.len() > 1 {
let limit = if error_codes.len() > 9 { 9 } else { error_codes.len() };
- self.failure(&format!(
+ self.failure(format!(
"Some errors have detailed explanations: {}{}",
error_codes[..limit].join(", "),
if error_codes.len() > 9 { "..." } else { "." }
));
- self.failure(&format!(
+ self.failure(format!(
"For more information about an error, try \
`rustc --explain {}`.",
&error_codes[0]
));
} else {
- self.failure(&format!(
+ self.failure(format!(
"For more information about this error, try \
`rustc --explain {}`.",
&error_codes[0]
@@ -1595,7 +1603,7 @@ impl HandlerInner {
// This is technically `self.treat_err_as_bug()` but `delay_span_bug` is called before
// incrementing `err_count` by one, so we need to +1 the comparing.
// FIXME: Would be nice to increment err_count in a more coherent way.
- if self.flags.treat_err_as_bug.map_or(false, |c| {
+ if self.flags.treat_err_as_bug.is_some_and(|c| {
self.err_count() + self.lint_err_count + self.delayed_bug_count() + 1 >= c.get()
}) {
// FIXME: don't abort here if report_delayed_bugs is off
@@ -1663,7 +1671,7 @@ impl HandlerInner {
if bug.level != Level::DelayedBug {
// NOTE(eddyb) not panicking here because we're already producing
// an ICE, and the more information the merrier.
- bug.note(&format!(
+ bug.note(format!(
"`flushed_delayed` got diagnostic with level {:?}, \
instead of the expected `DelayedBug`",
bug.level,
@@ -1732,7 +1740,7 @@ impl DelayedDiagnostic {
}
fn decorate(mut self) -> Diagnostic {
- self.inner.note(&format!("delayed at {}", self.note));
+ self.inner.note(format!("delayed at {}\n{}", self.inner.emitted_at, self.note));
self.inner
}
}
@@ -1831,7 +1839,7 @@ pub fn add_elided_lifetime_in_path_suggestion(
if incl_angl_brckt { format!("<{}>", anon_lts) } else { format!("{}, ", anon_lts) };
diag.span_suggestion_verbose(
insertion_span.shrink_to_hi(),
- &format!("indicate the anonymous lifetime{}", pluralize!(n)),
+ format!("indicate the anonymous lifetime{}", pluralize!(n)),
suggestion,
Applicability::MachineApplicable,
);
diff --git a/compiler/rustc_errors/src/lock.rs b/compiler/rustc_errors/src/lock.rs
index 7db262abf..bd5cf49b5 100644
--- a/compiler/rustc_errors/src/lock.rs
+++ b/compiler/rustc_errors/src/lock.rs
@@ -19,8 +19,7 @@ pub fn acquire_global_lock(name: &str) -> Box<dyn Any> {
use windows::{
core::PCSTR,
Win32::Foundation::{CloseHandle, HANDLE, WAIT_ABANDONED, WAIT_OBJECT_0},
- Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject},
- Win32::System::WindowsProgramming::INFINITE,
+ Win32::System::Threading::{CreateMutexA, ReleaseMutex, WaitForSingleObject, INFINITE},
};
struct Handle(HANDLE);
diff --git a/compiler/rustc_errors/src/tests.rs b/compiler/rustc_errors/src/tests.rs
index 52103e460..0e729b716 100644
--- a/compiler/rustc_errors/src/tests.rs
+++ b/compiler/rustc_errors/src/tests.rs
@@ -2,7 +2,7 @@ use crate::error::{TranslateError, TranslateErrorKind};
use crate::fluent_bundle::*;
use crate::translation::Translate;
use crate::FluentBundle;
-use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::{IntoDynSyncSend, Lrc};
use rustc_error_messages::fluent_bundle::resolver::errors::{ReferenceKind, ResolverError};
use rustc_error_messages::langid;
use rustc_error_messages::DiagnosticMessage;
@@ -27,10 +27,14 @@ fn make_dummy(ftl: &'static str) -> Dummy {
let langid_en = langid!("en-US");
#[cfg(parallel_compiler)]
- let mut bundle = FluentBundle::new_concurrent(vec![langid_en]);
+ let mut bundle: FluentBundle =
+ IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new_concurrent(vec![
+ langid_en,
+ ]));
#[cfg(not(parallel_compiler))]
- let mut bundle = FluentBundle::new(vec![langid_en]);
+ let mut bundle: FluentBundle =
+ IntoDynSyncSend(crate::fluent_bundle::bundle::FluentBundle::new(vec![langid_en]));
bundle.add_resource(resource).expect("Failed to add FTL resources to the bundle.");
diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml
index c971714e0..2dae0e3f5 100644
--- a/compiler/rustc_expand/Cargo.toml
+++ b/compiler/rustc_expand/Cargo.toml
@@ -16,6 +16,7 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_expand/messages.ftl b/compiler/rustc_expand/messages.ftl
index 5d999d0db..6c7e68246 100644
--- a/compiler/rustc_expand/messages.ftl
+++ b/compiler/rustc_expand/messages.ftl
@@ -1,138 +1,142 @@
-expand_explain_doc_comment_outer =
- outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
-
-expand_explain_doc_comment_inner =
- inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
-
-expand_expr_repeat_no_syntax_vars =
- attempted to repeat an expression containing no syntax variables matched as repeating at this depth
-
-expand_must_repeat_once =
- this must repeat at least once
-
-expand_count_repetition_misplaced =
- `count` can not be placed inside the inner-most repetition
-
-expand_meta_var_expr_unrecognized_var =
- variable `{$key}` is not recognized in meta-variable expression
-
-expand_var_still_repeating =
- variable '{$ident}' is still repeating at this depth
-
-expand_meta_var_dif_seq_matchers = {$msg}
-
-expand_macro_const_stability =
- macros cannot have const stability attributes
- .label = invalid const stability attribute
- .label2 = const stability attribute affects this macro
-
-expand_macro_body_stability =
- macros cannot have body stability attributes
- .label = invalid body stability attribute
- .label2 = body stability attribute affects this macro
-
-expand_resolve_relative_path =
- cannot resolve relative path in non-file source `{$path}`
+expand_arg_not_attributes =
+ second argument must be `attributes`
expand_attr_no_arguments =
attribute must have either one or two arguments
-expand_not_a_meta_item =
- not a meta item
-
-expand_only_one_word =
- must only be one word
-
-expand_cannot_be_name_of_macro =
- `{$trait_ident}` cannot be a name of {$macro_type} macro
+expand_attribute_meta_item =
+ attribute must be a meta item, not a literal
-expand_arg_not_attributes =
- second argument must be `attributes`
+expand_attribute_single_word =
+ attribute must only be a single word
expand_attributes_wrong_form =
attribute must be of form: `attributes(foo, bar)`
-expand_attribute_meta_item =
- attribute must be a meta item, not a literal
+expand_cannot_be_name_of_macro =
+ `{$trait_ident}` cannot be a name of {$macro_type} macro
-expand_attribute_single_word =
- attribute must only be a single word
+expand_count_repetition_misplaced =
+ `count` can not be placed inside the inner-most repetition
-expand_helper_attribute_name_invalid =
- `{$name}` cannot be a name of derive helper attribute
+expand_duplicate_matcher_binding = duplicate matcher binding
+ .label = duplicate binding
+ .label2 = previous binding
expand_expected_comma_in_list =
expected token: `,`
-expand_only_one_argument =
- {$name} takes 1 argument
+expand_explain_doc_comment_inner =
+ inner doc comments expand to `#![doc = "..."]`, which is what this macro attempted to match
-expand_takes_no_arguments =
- {$name} takes no arguments
+expand_explain_doc_comment_outer =
+ outer doc comments expand to `#[doc = "..."]`, which is what this macro attempted to match
+
+expand_expr_repeat_no_syntax_vars =
+ attempted to repeat an expression containing no syntax variables matched as repeating at this depth
expand_feature_included_in_edition =
the feature `{$feature}` is included in the Rust {$edition} edition
+expand_feature_not_allowed =
+ the feature `{$name}` is not in the list of allowed features
+
expand_feature_removed =
feature has been removed
.label = feature has been removed
.reason = {$reason}
-expand_feature_not_allowed =
- the feature `{$name}` is not in the list of allowed features
-
-expand_recursion_limit_reached =
- recursion limit reached while expanding `{$descr}`
- .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+expand_helper_attribute_name_invalid =
+ `{$name}` cannot be a name of derive helper attribute
-expand_malformed_feature_attribute =
- malformed `feature` attribute input
- .expected = expected just one word
+expand_incomplete_parse =
+ macro expansion ignores token `{$token}` and any following
+ .label = caused by the macro expansion here
+ .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
+ .suggestion_add_semi = you might be missing a semicolon here
-expand_remove_expr_not_supported =
- removing an expression is not supported in this position
+expand_invalid_cfg_expected_syntax = expected syntax is
+expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
expand_invalid_cfg_no_parens = `cfg` is not followed by parentheses
expand_invalid_cfg_no_predicate = `cfg` predicate is not specified
-expand_invalid_cfg_multiple_predicates = multiple `cfg` predicates are specified
expand_invalid_cfg_predicate_literal = `cfg` predicate key cannot be a literal
-expand_invalid_cfg_expected_syntax = expected syntax is
+expand_macro_body_stability =
+ macros cannot have body stability attributes
+ .label = invalid body stability attribute
+ .label2 = body stability attribute affects this macro
-expand_wrong_fragment_kind =
- non-{$kind} macro in {$kind} position: {$name}
+expand_macro_const_stability =
+ macros cannot have const stability attributes
+ .label = invalid const stability attribute
+ .label2 = const stability attribute affects this macro
-expand_unsupported_key_value =
- key-value macro attributes are not supported
+expand_malformed_feature_attribute =
+ malformed `feature` attribute input
+ .expected = expected just one word
-expand_incomplete_parse =
- macro expansion ignores token `{$token}` and any following
- .label = caused by the macro expansion here
- .note = the usage of `{$macro_path}!` is likely invalid in {$kind_name} context
- .suggestion_add_semi = you might be missing a semicolon here
+expand_meta_var_dif_seq_matchers = {$msg}
-expand_remove_node_not_supported =
- removing {$descr} is not supported in this position
+expand_meta_var_expr_unrecognized_var =
+ variable `{$key}` is not recognized in meta-variable expression
expand_module_circular =
circular modules: {$modules}
-expand_module_in_block =
- cannot declare a non-inline module inside a block unless it has a path attribute
- .note = maybe `use` the module `{$name}` instead of redeclaring it
-
expand_module_file_not_found =
file not found for module `{$name}`
.help = to create the module `{$name}`, create file "{$default_path}" or "{$secondary_path}"
+expand_module_in_block =
+ cannot declare a non-inline module inside a block unless it has a path attribute
+ .note = maybe `use` the module `{$name}` instead of redeclaring it
+
expand_module_multiple_candidates =
file for module `{$name}` found at both "{$default_path}" and "{$secondary_path}"
.help = delete or rename one of them to remove the ambiguity
-expand_trace_macro = trace_macro
+expand_must_repeat_once =
+ this must repeat at least once
+
+expand_not_a_meta_item =
+ not a meta item
+
+expand_only_one_argument =
+ {$name} takes 1 argument
+
+expand_only_one_word =
+ must only be one word
+
+expand_proc_macro_derive_tokens =
+ proc-macro derive produced unparsable tokens
expand_proc_macro_panicked =
proc macro panicked
.help = message: {$message}
-expand_proc_macro_derive_tokens =
- proc-macro derive produced unparsable tokens
+expand_recursion_limit_reached =
+ recursion limit reached while expanding `{$descr}`
+ .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+expand_remove_expr_not_supported =
+ removing an expression is not supported in this position
+
+expand_remove_node_not_supported =
+ removing {$descr} is not supported in this position
+
+expand_resolve_relative_path =
+ cannot resolve relative path in non-file source `{$path}`
+
+expand_takes_no_arguments =
+ {$name} takes no arguments
+
+expand_trace_macro = trace_macro
+
+expand_unsupported_key_value =
+ key-value macro attributes are not supported
+
+expand_var_still_repeating =
+ variable '{$ident}' is still repeating at this depth
+
+expand_wrong_fragment_kind =
+ non-{$kind} macro in {$kind} position: {$name}
diff --git a/compiler/rustc_expand/src/base.rs b/compiler/rustc_expand/src/base.rs
index caa2a201c..4671adccc 100644
--- a/compiler/rustc_expand/src/base.rs
+++ b/compiler/rustc_expand/src/base.rs
@@ -15,7 +15,8 @@ use rustc_attr::{self as attr, Deprecation, Stability};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::{self, Lrc};
use rustc_errors::{
- Applicability, DiagnosticBuilder, ErrorGuaranteed, IntoDiagnostic, MultiSpan, PResult,
+ Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, IntoDiagnostic,
+ MultiSpan, PResult,
};
use rustc_lint_defs::builtin::PROC_MACRO_BACK_COMPAT;
use rustc_lint_defs::{BufferedEarlyLint, BuiltinLintDiagnostics, RegisteredTools};
@@ -653,13 +654,13 @@ pub enum SyntaxExtensionKind {
/// A token-based function-like macro.
Bang(
/// An expander with signature TokenStream -> TokenStream.
- Box<dyn BangProcMacro + sync::Sync + sync::Send>,
+ Box<dyn BangProcMacro + sync::DynSync + sync::DynSend>,
),
/// An AST-based function-like macro.
LegacyBang(
/// An expander with signature TokenStream -> AST.
- Box<dyn TTMacroExpander + sync::Sync + sync::Send>,
+ Box<dyn TTMacroExpander + sync::DynSync + sync::DynSend>,
),
/// A token-based attribute macro.
@@ -667,7 +668,7 @@ pub enum SyntaxExtensionKind {
/// An expander with signature (TokenStream, TokenStream) -> TokenStream.
/// The first TokenSteam is the attribute itself, the second is the annotated item.
/// The produced TokenSteam replaces the input TokenSteam.
- Box<dyn AttrProcMacro + sync::Sync + sync::Send>,
+ Box<dyn AttrProcMacro + sync::DynSync + sync::DynSend>,
),
/// An AST-based attribute macro.
@@ -675,7 +676,7 @@ pub enum SyntaxExtensionKind {
/// An expander with signature (AST, AST) -> AST.
/// The first AST fragment is the attribute itself, the second is the annotated item.
/// The produced AST fragment replaces the input AST fragment.
- Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
+ Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),
/// A trivial attribute "macro" that does nothing,
@@ -692,14 +693,14 @@ pub enum SyntaxExtensionKind {
/// is handled identically to `LegacyDerive`. It should be migrated to
/// a token-based representation like `Bang` and `Attr`, instead of
/// using `MultiItemModifier`.
- Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
+ Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),
/// An AST-based derive macro.
LegacyDerive(
/// An expander with signature AST -> AST.
/// The produced AST fragment is appended to the input AST fragment.
- Box<dyn MultiItemModifier + sync::Sync + sync::Send>,
+ Box<dyn MultiItemModifier + sync::DynSync + sync::DynSend>,
),
}
@@ -779,7 +780,7 @@ impl SyntaxExtension {
let allow_internal_unsafe = attr::contains_name(attrs, sym::allow_internal_unsafe);
let local_inner_macros = attr::find_by_name(attrs, sym::macro_export)
.and_then(|macro_export| macro_export.meta_item_list())
- .map_or(false, |l| attr::list_contains_name(&l, sym::local_inner_macros));
+ .is_some_and(|l| attr::list_contains_name(&l, sym::local_inner_macros));
let collapse_debuginfo = attr::contains_name(attrs, sym::collapse_debuginfo);
tracing::debug!(?local_inner_macros, ?collapse_debuginfo, ?allow_internal_unsafe);
@@ -992,7 +993,6 @@ pub struct ExpansionData {
pub depth: usize,
pub module: Rc<ModuleData>,
pub dir_ownership: DirOwnership,
- pub prior_type_ascription: Option<(Span, bool)>,
/// Some parent node that is close to this macro call
pub lint_node_id: NodeId,
pub is_trailing_mac: bool,
@@ -1043,7 +1043,6 @@ impl<'a> ExtCtxt<'a> {
depth: 0,
module: Default::default(),
dir_ownership: DirOwnership::Owned { relative: None },
- prior_type_ascription: None,
lint_node_id: ast::CRATE_NODE_ID,
is_trailing_mac: false,
},
@@ -1112,7 +1111,7 @@ impl<'a> ExtCtxt<'a> {
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
- msg: &str,
+ msg: impl Into<DiagnosticMessage>,
) -> DiagnosticBuilder<'a, ErrorGuaranteed> {
self.sess.parse_sess.span_diagnostic.struct_span_err(sp, msg)
}
@@ -1134,21 +1133,21 @@ impl<'a> ExtCtxt<'a> {
/// Compilation will be stopped in the near future (at the end of
/// the macro expansion phase).
#[rustc_lint_diagnostics]
- pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ pub fn span_err<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.parse_sess.span_diagnostic.span_err(sp, msg);
}
#[rustc_lint_diagnostics]
- pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: &str) {
+ pub fn span_warn<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) {
self.sess.parse_sess.span_diagnostic.span_warn(sp, msg);
}
- pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: &str) -> ! {
+ pub fn span_bug<S: Into<MultiSpan>>(&self, sp: S, msg: impl Into<DiagnosticMessage>) -> ! {
self.sess.parse_sess.span_diagnostic.span_bug(sp, msg);
}
pub fn trace_macros_diag(&mut self) {
for (span, notes) in self.expansions.iter() {
let mut db = self.sess.parse_sess.create_note(errors::TraceMacro { span: *span });
for note in notes {
- db.note(note);
+ db.note(note.clone());
}
db.emit();
}
@@ -1450,7 +1449,7 @@ fn pretty_printing_compatibility_hack(item: &Item, sess: &ParseSess) -> bool {
&& version
.next()
.and_then(|c| c.parse::<u32>().ok())
- .map_or(false, |v| v < 6)
+ .is_some_and(|v| v < 6)
};
if crate_matches {
diff --git a/compiler/rustc_expand/src/errors.rs b/compiler/rustc_expand/src/errors.rs
index e5102a952..e3a0ae357 100644
--- a/compiler/rustc_expand/src/errors.rs
+++ b/compiler/rustc_expand/src/errors.rs
@@ -397,3 +397,13 @@ pub struct ProcMacroDeriveTokens {
#[primary_span]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(expand_duplicate_matcher_binding)]
+pub struct DuplicateMatcherBinding {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(expand_label2)]
+ pub prev: Span,
+}
diff --git a/compiler/rustc_expand/src/expand.rs b/compiler/rustc_expand/src/expand.rs
index ec4091154..ce0093c7d 100644
--- a/compiler/rustc_expand/src/expand.rs
+++ b/compiler/rustc_expand/src/expand.rs
@@ -657,8 +657,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.parse_ast_fragment(tok_result, fragment_kind, &mac.path, span)
}
SyntaxExtensionKind::LegacyBang(expander) => {
- let prev = self.cx.current_expansion.prior_type_ascription;
- self.cx.current_expansion.prior_type_ascription = mac.prior_type_ascription;
let tok_result = expander.expand(self.cx, span, mac.args.tokens.clone());
let result = if let Some(result) = fragment_kind.make_from(tok_result) {
result
@@ -666,7 +664,6 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
self.error_wrong_fragment_kind(fragment_kind, &mac, span);
fragment_kind.dummy(span)
};
- self.cx.current_expansion.prior_type_ascription = prev;
result
}
_ => unreachable!(),
@@ -725,7 +722,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
});
}
};
- if fragment_kind == AstFragmentKind::Expr && items.is_empty() {
+ if matches!(
+ fragment_kind,
+ AstFragmentKind::Expr | AstFragmentKind::MethodReceiverExpr
+ ) && items.is_empty()
+ {
self.cx.emit_err(RemoveExprNotSupported { span });
fragment_kind.dummy(span)
} else {
@@ -800,7 +801,7 @@ impl<'a, 'b> MacroExpander<'a, 'b> {
&self.cx.sess.parse_sess,
sym::proc_macro_hygiene,
span,
- &format!("custom attributes cannot be applied to {}", kind),
+ format!("custom attributes cannot be applied to {}", kind),
)
.emit();
}
@@ -1598,7 +1599,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
cfg_pos = Some(pos); // a cfg attr found, no need to search anymore
break;
} else if attr_pos.is_none()
- && !name.map_or(false, rustc_feature::is_builtin_attr_name)
+ && !name.is_some_and(rustc_feature::is_builtin_attr_name)
{
attr_pos = Some(pos); // a non-cfg attr found, still may find a cfg attr
}
@@ -1646,7 +1647,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
let current_span = if let Some(sp) = span { sp.to(attr.span) } else { attr.span };
span = Some(current_span);
- if attrs.peek().map_or(false, |next_attr| next_attr.doc_str().is_some()) {
+ if attrs.peek().is_some_and(|next_attr| next_attr.doc_str().is_some()) {
continue;
}
@@ -1667,7 +1668,7 @@ impl<'a, 'b> InvocationCollector<'a, 'b> {
&UNUSED_ATTRIBUTES,
attr.span,
self.cx.current_expansion.lint_node_id,
- &format!("unused attribute `{}`", attr_name),
+ format!("unused attribute `{}`", attr_name),
BuiltinLintDiagnostics::UnusedBuiltinAttribute {
attr_name,
macro_name: pprust::path_to_string(&call.path),
@@ -1949,6 +1950,6 @@ impl<'feat> ExpansionConfig<'feat> {
}
fn proc_macro_hygiene(&self) -> bool {
- self.features.map_or(false, |features| features.proc_macro_hygiene)
+ self.features.is_some_and(|features| features.proc_macro_hygiene)
}
}
diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs
index ced7531c3..83a5043b0 100644
--- a/compiler/rustc_expand/src/lib.rs
+++ b/compiler/rustc_expand/src/lib.rs
@@ -21,7 +21,7 @@ extern crate tracing;
extern crate proc_macro as pm;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
mod placeholders;
mod proc_macro_server;
diff --git a/compiler/rustc_expand/src/mbe/diagnostics.rs b/compiler/rustc_expand/src/mbe/diagnostics.rs
index 355722922..cb8b4899e 100644
--- a/compiler/rustc_expand/src/mbe/diagnostics.rs
+++ b/compiler/rustc_expand/src/mbe/diagnostics.rs
@@ -48,7 +48,7 @@ pub(super) fn failed_to_match_macro<'cx>(
let span = token.span.substitute_dummy(sp);
- let mut err = cx.struct_span_err(span, &parse_failure_msg(&token));
+ 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");
@@ -170,7 +170,7 @@ impl<'a, 'cx, 'matcher> Tracker<'matcher> for CollectTrackerAndEmitter<'a, 'cx,
}
Error(err_sp, msg) => {
let span = err_sp.substitute_dummy(self.root_span);
- self.cx.struct_span_err(span, msg).emit();
+ self.cx.struct_span_err(span, msg.as_str()).emit();
self.result = Some(DummyResult::any(span));
}
ErrorReported(_) => self.result = Some(DummyResult::any(self.root_span)),
diff --git a/compiler/rustc_expand/src/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs
index 5be134f4e..34f998274 100644
--- a/compiler/rustc_expand/src/mbe/macro_check.rs
+++ b/compiler/rustc_expand/src/mbe/macro_check.rs
@@ -104,12 +104,13 @@
//! Kleene operators under which a meta-variable is repeating is the concatenation of the stacks
//! stored when entering a macro definition starting from the state in which the meta-variable is
//! bound.
+use crate::errors;
use crate::mbe::{KleeneToken, TokenTree};
use rustc_ast::token::{Delimiter, Token, TokenKind};
use rustc_ast::{NodeId, DUMMY_NODE_ID};
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::MultiSpan;
+use rustc_errors::{DiagnosticMessage, MultiSpan};
use rustc_session::lint::builtin::{META_VARIABLE_MISUSE, MISSING_FRAGMENT_SPECIFIER};
use rustc_session::parse::ParseSess;
use rustc_span::symbol::kw;
@@ -281,10 +282,7 @@ fn check_binders(
// Duplicate binders at the top-level macro definition are errors. The lint is only
// for nested macro definitions.
sess.span_diagnostic
- .struct_span_err(span, "duplicate matcher binding")
- .span_label(span, "duplicate binding")
- .span_label(prev_info.span, "previous binding")
- .emit();
+ .emit_err(errors::DuplicateMatcherBinding { span, prev: prev_info.span });
*valid = false;
} else {
binders.insert(name, BinderInfo { span, ops: ops.into() });
@@ -595,7 +593,7 @@ fn check_ops_is_prefix(
return;
}
}
- buffer_lint(sess, span.into(), node_id, &format!("unknown macro variable `{}`", name));
+ buffer_lint(sess, span.into(), node_id, format!("unknown macro variable `{}`", name));
}
/// Returns whether `binder_ops` is a prefix of `occurrence_ops`.
@@ -628,7 +626,7 @@ fn ops_is_prefix(
if i >= occurrence_ops.len() {
let mut span = MultiSpan::from_span(span);
span.push_span_label(binder.span, "expected repetition");
- let message = &format!("variable '{}' is still repeating at this depth", name);
+ let message = format!("variable '{}' is still repeating at this depth", name);
buffer_lint(sess, span, node_id, message);
return;
}
@@ -644,7 +642,12 @@ fn ops_is_prefix(
}
}
-fn buffer_lint(sess: &ParseSess, span: MultiSpan, node_id: NodeId, message: &str) {
+fn buffer_lint(
+ sess: &ParseSess,
+ span: MultiSpan,
+ node_id: NodeId,
+ message: impl Into<DiagnosticMessage>,
+) {
// Macros loaded from other crates have dummy node ids.
if node_id != DUMMY_NODE_ID {
sess.buffer_lint(&META_VARIABLE_MISUSE, span, node_id, message);
diff --git a/compiler/rustc_expand/src/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs
index 283e68a68..1c222fb4a 100644
--- a/compiler/rustc_expand/src/mbe/macro_parser.rs
+++ b/compiler/rustc_expand/src/mbe/macro_parser.rs
@@ -88,6 +88,7 @@ use rustc_span::Span;
use std::borrow::Cow;
use std::collections::hash_map::Entry::{Occupied, Vacant};
use std::fmt::Display;
+use std::rc::Rc;
/// A unit within a matcher that a `MatcherPos` can refer to. Similar to (and derived from)
/// `mbe::TokenTree`, but designed specifically for fast and easy traversal during matching.
@@ -257,10 +258,10 @@ struct MatcherPos {
/// against the relevant metavar by the black box parser. An element will be a `MatchedSeq` if
/// the corresponding metavar decl is within a sequence.
///
- /// It is critical to performance that this is an `Lrc`, because it gets cloned frequently when
+ /// It is critical to performance that this is an `Rc`, because it gets cloned frequently when
/// processing sequences. Mostly for sequence-ending possibilities that must be tried but end
/// up failing.
- matches: Lrc<Vec<NamedMatch>>,
+ matches: Rc<Vec<NamedMatch>>,
}
// This type is used a lot. Make sure it doesn't unintentionally get bigger.
@@ -272,7 +273,7 @@ impl MatcherPos {
/// and both are hot enough to be always worth inlining.
#[inline(always)]
fn push_match(&mut self, metavar_idx: usize, seq_depth: usize, m: NamedMatch) {
- let matches = Lrc::make_mut(&mut self.matches);
+ let matches = Rc::make_mut(&mut self.matches);
match seq_depth {
0 => {
// We are not within a sequence. Just append `m`.
@@ -427,7 +428,7 @@ pub struct TtParser {
/// Pre-allocate an empty match array, so it can be cloned cheaply for macros with many rules
/// that have no metavars.
- empty_matches: Lrc<Vec<NamedMatch>>,
+ empty_matches: Rc<Vec<NamedMatch>>,
}
impl TtParser {
@@ -437,7 +438,7 @@ impl TtParser {
cur_mps: vec![],
next_mps: vec![],
bb_mps: vec![],
- empty_matches: Lrc::new(vec![]),
+ empty_matches: Rc::new(vec![]),
}
}
@@ -507,7 +508,7 @@ impl TtParser {
// Try zero matches of this sequence, by skipping over it.
self.cur_mps.push(MatcherPos {
idx: idx_first_after,
- matches: Lrc::clone(&mp.matches),
+ matches: Rc::clone(&mp.matches),
});
}
@@ -521,7 +522,7 @@ impl TtParser {
// processed next time around the loop.
let ending_mp = MatcherPos {
idx: mp.idx + 1, // +1 skips the Kleene op
- matches: Lrc::clone(&mp.matches),
+ matches: Rc::clone(&mp.matches),
};
self.cur_mps.push(ending_mp);
@@ -537,7 +538,7 @@ impl TtParser {
// 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: Lrc::clone(&mp.matches),
+ matches: Rc::clone(&mp.matches),
};
self.cur_mps.push(ending_mp);
@@ -587,9 +588,9 @@ impl TtParser {
if *token == token::Eof {
Some(match eof_mps {
EofMatcherPositions::One(mut eof_mp) => {
- // Need to take ownership of the matches from within the `Lrc`.
- Lrc::make_mut(&mut eof_mp.matches);
- let matches = Lrc::try_unwrap(eof_mp.matches).unwrap().into_iter();
+ // Need to take ownership of the matches from within the `Rc`.
+ Rc::make_mut(&mut eof_mp.matches);
+ let matches = Rc::try_unwrap(eof_mp.matches).unwrap().into_iter();
self.nameize(matcher, matches)
}
EofMatcherPositions::Multiple => {
diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs
index 5679cdcbb..e4c65a204 100644
--- a/compiler/rustc_expand/src/mbe/macro_rules.rs
+++ b/compiler/rustc_expand/src/mbe/macro_rules.rs
@@ -250,8 +250,7 @@ fn expand_macro<'cx>(
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;
+ let p = Parser::new(sess, tts, false, None);
if is_local {
cx.resolver.record_macro_rule_usage(node_id, i);
@@ -341,7 +340,7 @@ pub(super) fn try_match_macro<'matcher, T: Tracker<'matcher>>(
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.
+ // Merge the gated spans from parsing the matcher with the preexisting ones.
sess.gated_spans.merge(gated_spans_snapshot);
return Ok((i, named_matches));
@@ -475,7 +474,7 @@ pub fn compile_declarative_macro(
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);
+ 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();
@@ -484,7 +483,7 @@ pub fn compile_declarative_macro(
Error(sp, msg) => {
sess.parse_sess
.span_diagnostic
- .struct_span_err(sp.substitute_dummy(def.span), &msg)
+ .struct_span_err(sp.substitute_dummy(def.span), msg)
.emit();
return dummy_syn_ext();
}
@@ -556,7 +555,7 @@ pub fn compile_declarative_macro(
let (transparency, transparency_error) = attr::find_transparency(&def.attrs, macro_rules);
match transparency_error {
Some(TransparencyError::UnknownTransparency(value, span)) => {
- diag.span_err(span, &format!("unknown macro transparency: `{}`", value));
+ diag.span_err(span, format!("unknown macro transparency: `{}`", value));
}
Some(TransparencyError::MultipleTransparencyAttrs(old_span, new_span)) => {
diag.span_err(vec![old_span, new_span], "multiple macro transparency attributes");
@@ -873,7 +872,7 @@ impl<'tt> FirstSets<'tt> {
}
}
-// Most `mbe::TokenTree`s are pre-existing in the matcher, but some are defined
+// Most `mbe::TokenTree`s are preexisting in the matcher, but some are defined
// implicitly, such as opening/closing delimiters and sequence repetition ops.
// This type encapsulates both kinds. It implements `Clone` while avoiding the
// need for `mbe::TokenTree` to implement `Clone`.
@@ -1165,7 +1164,7 @@ fn check_matcher_core<'tt>(
let sp = next_token.span();
let mut err = sess.span_diagnostic.struct_span_err(
sp,
- &format!(
+ format!(
"`${name}:{frag}` {may_be} followed by `{next}`, which \
is not allowed for `{frag}` fragments",
name = name,
@@ -1197,13 +1196,13 @@ fn check_matcher_core<'tt>(
match possible {
&[] => {}
&[t] => {
- err.note(&format!(
+ err.note(format!(
"only {} is allowed after `{}` fragments",
t, kind,
));
}
ts => {
- err.note(&format!(
+ err.note(format!(
"{}{} or {}",
msg,
ts[..ts.len() - 1].to_vec().join(", "),
diff --git a/compiler/rustc_expand/src/mbe/metavar_expr.rs b/compiler/rustc_expand/src/mbe/metavar_expr.rs
index fb3a00d86..6e9196150 100644
--- a/compiler/rustc_expand/src/mbe/metavar_expr.rs
+++ b/compiler/rustc_expand/src/mbe/metavar_expr.rs
@@ -78,7 +78,7 @@ fn check_trailing_token<'sess>(
if let Some(tt) = iter.next() {
let mut diag = sess
.span_diagnostic
- .struct_span_err(tt.span(), &format!("unexpected token: {}", pprust::tt_to_string(tt)));
+ .struct_span_err(tt.span(), format!("unexpected token: {}", pprust::tt_to_string(tt)));
diag.span_note(tt.span(), "meta-variable expression must not have trailing tokens");
Err(diag)
} else {
@@ -137,11 +137,11 @@ fn parse_ident<'sess>(
let token_str = pprust::token_to_string(token);
let mut err = sess.span_diagnostic.struct_span_err(
span,
- &format!("expected identifier, found `{}`", &token_str)
+ format!("expected identifier, found `{}`", &token_str)
);
err.span_suggestion(
token.span,
- &format!("try removing `{}`", &token_str),
+ format!("try removing `{}`", &token_str),
"",
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_expand/src/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs
index bc298b0ad..b2bdf9c7e 100644
--- a/compiler/rustc_expand/src/mbe/quoted.rs
+++ b/compiler/rustc_expand/src/mbe/quoted.rs
@@ -85,7 +85,7 @@ pub(super) fn parse(
frag.name
);
sess.span_diagnostic
- .struct_span_err(span, &msg)
+ .struct_span_err(span, msg)
.help(VALID_FRAGMENT_NAMES_MSG)
.emit();
token::NonterminalKind::Ident
@@ -195,7 +195,7 @@ fn parse_tree(
_ => {
let tok = pprust::token_kind_to_string(&token::OpenDelim(delim));
let msg = format!("expected `(` or `{{`, found `{}`", tok);
- sess.span_diagnostic.span_err(delim_span.entire(), &msg);
+ sess.span_diagnostic.span_err(delim_span.entire(), msg);
}
}
}
@@ -246,7 +246,7 @@ fn parse_tree(
"expected identifier, found `{}`",
pprust::token_to_string(&token),
);
- sess.span_diagnostic.span_err(token.span, &msg);
+ sess.span_diagnostic.span_err(token.span, msg);
TokenTree::MetaVar(token.span, Ident::empty())
}
@@ -358,7 +358,7 @@ fn parse_sep_and_kleene_op(
// For example, `macro_rules! foo { ( ${length()} ) => {} }`
fn span_dollar_dollar_or_metavar_in_the_lhs_err(sess: &ParseSess, token: &Token) {
sess.span_diagnostic
- .span_err(token.span, &format!("unexpected token: {}", pprust::token_to_string(token)));
+ .span_err(token.span, format!("unexpected token: {}", pprust::token_to_string(token)));
sess.span_diagnostic.span_note_without_error(
token.span,
"`$$` and meta-variable expressions are not allowed inside macro parameter definitions",
diff --git a/compiler/rustc_expand/src/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs
index a07cb6517..d523d3eac 100644
--- a/compiler/rustc_expand/src/mbe/transcribe.rs
+++ b/compiler/rustc_expand/src/mbe/transcribe.rs
@@ -510,7 +510,7 @@ fn out_of_bounds_err<'a>(
must be less than {max}"
)
};
- cx.struct_span_err(span, &msg)
+ cx.struct_span_err(span, msg)
}
fn transcribe_metavar_expr<'a>(
diff --git a/compiler/rustc_expand/src/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs
index 03bb5c1df..e9af688ee 100644
--- a/compiler/rustc_expand/src/placeholders.rs
+++ b/compiler/rustc_expand/src/placeholders.rs
@@ -21,7 +21,6 @@ pub fn placeholder(
delim: ast::MacDelimiter::Parenthesis,
tokens: ast::tokenstream::TokenStream::new(Vec::new()),
}),
- prior_type_ascription: None,
})
}
diff --git a/compiler/rustc_expand/src/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs
index 26bc216f6..41b24407f 100644
--- a/compiler/rustc_expand/src/proc_macro.rs
+++ b/compiler/rustc_expand/src/proc_macro.rs
@@ -95,7 +95,7 @@ impl base::AttrProcMacro for AttrProcMacro {
|e| {
let mut err = ecx.struct_span_err(span, "custom attribute panicked");
if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
+ err.help(format!("message: {}", s));
}
err.emit()
},
@@ -148,7 +148,7 @@ impl MultiItemModifier for DeriveProcMacro {
Err(e) => {
let mut err = ecx.struct_span_err(span, "proc-macro derive panicked");
if let Some(s) = e.as_str() {
- err.help(&format!("message: {}", s));
+ err.help(format!("message: {}", s));
}
err.emit();
return ExpandResult::Ready(vec![]);
diff --git a/compiler/rustc_expand/src/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs
index 341ae1854..891e84a2f 100644
--- a/compiler/rustc_expand/src/proc_macro_server.rs
+++ b/compiler/rustc_expand/src/proc_macro_server.rs
@@ -18,7 +18,7 @@ use rustc_span::def_id::CrateNum;
use rustc_span::symbol::{self, sym, Symbol};
use rustc_span::{BytePos, FileName, Pos, SourceFile, Span};
use smallvec::{smallvec, SmallVec};
-use std::ops::Bound;
+use std::ops::{Bound, Range};
trait FromInternal<T> {
fn from_internal(x: T) -> Self;
@@ -61,6 +61,8 @@ impl FromInternal<token::LitKind> for LitKind {
token::StrRaw(n) => LitKind::StrRaw(n),
token::ByteStr => LitKind::ByteStr,
token::ByteStrRaw(n) => LitKind::ByteStrRaw(n),
+ token::CStr => LitKind::CStr,
+ token::CStrRaw(n) => LitKind::CStrRaw(n),
token::Err => LitKind::Err,
token::Bool => unreachable!(),
}
@@ -78,6 +80,8 @@ impl ToInternal<token::LitKind> for LitKind {
LitKind::StrRaw(n) => token::StrRaw(n),
LitKind::ByteStr => token::ByteStr,
LitKind::ByteStrRaw(n) => token::ByteStrRaw(n),
+ LitKind::CStr => token::CStr,
+ LitKind::CStrRaw(n) => token::CStrRaw(n),
LitKind::Err => token::Err,
}
}
@@ -436,6 +440,8 @@ impl server::FreeFunctions for Rustc<'_, '_> {
| token::LitKind::StrRaw(_)
| token::LitKind::ByteStr
| token::LitKind::ByteStrRaw(_)
+ | token::LitKind::CStr
+ | token::LitKind::CStrRaw(_)
| token::LitKind::Err => return Err(()),
token::LitKind::Integer | token::LitKind::Float => {}
}
@@ -634,6 +640,15 @@ impl server::Span for Rustc<'_, '_> {
span.source_callsite()
}
+ fn byte_range(&mut self, span: Self::Span) -> Range<usize> {
+ let source_map = self.sess().source_map();
+
+ let relative_start_pos = source_map.lookup_byte_offset(span.lo()).pos;
+ let relative_end_pos = source_map.lookup_byte_offset(span.hi()).pos;
+
+ Range { start: relative_start_pos.0 as usize, end: relative_end_pos.0 as usize }
+ }
+
fn start(&mut self, span: Self::Span) -> LineColumn {
let loc = self.sess().source_map().lookup_char_pos(span.lo());
LineColumn { line: loc.line, column: loc.col.to_usize() }
diff --git a/compiler/rustc_expand/src/tests.rs b/compiler/rustc_expand/src/tests.rs
index 480d95b77..8a5e09475 100644
--- a/compiler/rustc_expand/src/tests.rs
+++ b/compiler/rustc_expand/src/tests.rs
@@ -513,7 +513,7 @@ error: foo
}
#[test]
-fn non_overlaping() {
+fn non_overlapping() {
test_harness(
r#"
fn foo() {
@@ -552,7 +552,7 @@ error: foo
}
#[test]
-fn overlaping_start_and_end() {
+fn overlapping_start_and_end() {
test_harness(
r#"
fn foo() {
diff --git a/compiler/rustc_feature/src/accepted.rs b/compiler/rustc_feature/src/accepted.rs
index 3b9fc5e9a..0170d52e8 100644
--- a/compiler/rustc_feature/src/accepted.rs
+++ b/compiler/rustc_feature/src/accepted.rs
@@ -130,6 +130,8 @@ declare_features! (
(accepted, copy_closures, "1.26.0", Some(44490), None),
/// Allows `crate` in paths.
(accepted, crate_in_paths, "1.30.0", Some(45477), None),
+ /// Allows using `#[debugger_visualizer]` attribute.
+ (accepted, debugger_visualizer, "1.71.0", Some(95939), None),
/// Allows rustc to inject a default alloc_error_handler
(accepted, default_alloc_error_handler, "1.68.0", Some(66741), None),
/// Allows using assigning a default type to type parameters in algebraic data type definitions.
@@ -278,6 +280,8 @@ declare_features! (
(accepted, pub_restricted, "1.18.0", Some(32409), None),
/// Allows use of the postfix `?` operator in expressions.
(accepted, question_mark, "1.13.0", Some(31436), None),
+ /// Allows the use of raw-dylibs (RFC 2627).
+ (accepted, raw_dylib, "1.71.0", Some(58713), None),
/// Allows keywords to be escaped for use as identifiers.
(accepted, raw_identifiers, "1.30.0", Some(48589), None),
/// Allows relaxing the coherence rules such that
diff --git a/compiler/rustc_feature/src/active.rs b/compiler/rustc_feature/src/active.rs
index 052d312d9..dde9890df 100644
--- a/compiler/rustc_feature/src/active.rs
+++ b/compiler/rustc_feature/src/active.rs
@@ -164,6 +164,8 @@ declare_features! (
(active, link_cfg, "1.14.0", None, None),
/// Allows the `multiple_supertrait_upcastable` lint.
(active, multiple_supertrait_upcastable, "1.69.0", None, None),
+ /// Allow negative trait bounds. This is an internal-only feature for testing the trait solver!
+ (incomplete, negative_bounds, "1.71.0", None, None),
/// Allows using `#[omit_gdb_pretty_printer_section]`.
(active, omit_gdb_pretty_printer_section, "1.5.0", None, None),
/// Allows using `#[prelude_import]` on glob `use` items.
@@ -310,11 +312,17 @@ declare_features! (
/// Allows `async || body` closures.
(active, async_closure, "1.37.0", Some(62290), None),
/// Allows async functions to be declared, implemented, and used in traits.
- (incomplete, async_fn_in_trait, "1.66.0", Some(91611), None),
- /// Allows `extern "C-unwind" fn` to enable unwinding across ABI boundaries.
+ (active, async_fn_in_trait, "1.66.0", Some(91611), None),
+ /// Allows builtin # foo() syntax
+ (active, builtin_syntax, "1.71.0", Some(110680), None),
+ /// Allows `c"foo"` literals.
+ (active, c_str_literals, "1.71.0", Some(105723), None),
+ /// Treat `extern "C"` function as nounwind.
(active, c_unwind, "1.52.0", Some(74990), None),
/// Allows using C-variadics.
(active, c_variadic, "1.34.0", Some(44930), None),
+ /// Allows the use of `#[cfg(overflow_checks)` to check if integer overflow behaviour.
+ (active, cfg_overflow_checks, "1.71.0", Some(111466), None),
/// Allows the use of `#[cfg(sanitize = "option")]`; set when -Zsanitizer is used.
(active, cfg_sanitize, "1.41.0", Some(39699), None),
/// Allows `cfg(target_abi = "...")`.
@@ -329,6 +337,8 @@ declare_features! (
(active, cfg_target_thread_local, "1.7.0", Some(29594), None),
/// Allow conditional compilation depending on rust version
(active, cfg_version, "1.45.0", Some(64796), None),
+ /// Allows to use the `#[cfi_encoding = ""]` attribute.
+ (active, cfi_encoding, "1.71.0", Some(89653), None),
/// Allows `for<...>` on closures and generators.
(active, closure_lifetime_binder, "1.64.0", Some(97362), None),
/// Allows `#[track_caller]` on closures and generators.
@@ -363,8 +373,6 @@ declare_features! (
(active, custom_inner_attributes, "1.30.0", Some(54726), None),
/// Allows custom test frameworks with `#![test_runner]` and `#[test_case]`.
(active, custom_test_frameworks, "1.30.0", Some(50297), None),
- /// Allows using `#[debugger_visualizer]`.
- (active, debugger_visualizer, "1.62.0", Some(95939), None),
/// Allows declarative macros 2.0 (`macro`).
(active, decl_macro, "1.17.0", Some(39412), None),
/// Allows default type parameters to influence type inference.
@@ -485,8 +493,6 @@ declare_features! (
(active, precise_pointer_size_matching, "1.32.0", Some(56354), None),
/// Allows macro attributes on expressions, statements and non-inline modules.
(active, proc_macro_hygiene, "1.30.0", Some(54727), None),
- /// Allows the use of raw-dylibs (RFC 2627).
- (active, raw_dylib, "1.65.0", Some(58713), None),
/// Allows `&raw const $place_expr` and `&raw mut $place_expr` expressions.
(active, raw_ref_op, "1.41.0", Some(64490), None),
/// Allows using the `#[register_tool]` attribute.
@@ -496,7 +502,7 @@ declare_features! (
/// Allows `repr(simd)` and importing the various simd intrinsics.
(active, repr_simd, "1.4.0", Some(27731), None),
/// Allows return-position `impl Trait` in traits.
- (incomplete, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
+ (active, return_position_impl_trait_in_trait, "1.65.0", Some(91611), None),
/// Allows bounding the return type of AFIT/RPITIT.
(incomplete, return_type_notation, "1.70.0", Some(109417), None),
/// Allows `extern "rust-cold"`.
diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs
index c77292fdd..06f4a0b5e 100644
--- a/compiler/rustc_feature/src/builtin_attrs.rs
+++ b/compiler/rustc_feature/src/builtin_attrs.rs
@@ -24,6 +24,7 @@ pub type GatedCfg = (Symbol, Symbol, GateFn);
/// `cfg(...)`'s that are feature gated.
const GATED_CFGS: &[GatedCfg] = &[
// (name in cfg, feature, function to check if the feature is enabled)
+ (sym::overflow_checks, sym::cfg_overflow_checks, cfg_fn!(cfg_overflow_checks)),
(sym::target_abi, sym::cfg_target_abi, cfg_fn!(cfg_target_abi)),
(sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)),
(
@@ -403,16 +404,16 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
doc, Normal, template!(List: "hidden|inline|...", NameValueStr: "string"), DuplicatesOk
),
+ // Debugging
+ ungated!(
+ debugger_visualizer, Normal,
+ template!(List: r#"natvis_file = "...", gdb_script_file = "...""#), DuplicatesOk
+ ),
+
// ==========================================================================
// Unstable attributes:
// ==========================================================================
- // RFC #3191: #[debugger_visualizer] support
- gated!(
- debugger_visualizer, Normal, template!(List: r#"natvis_file = "...", gdb_script_file = "...""#),
- DuplicatesOk, experimental!(debugger_visualizer)
- ),
-
// Linking:
gated!(
naked, Normal, template!(Word), WarnFollowing, @only_local: true,
@@ -494,6 +495,12 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[
// RFC 2397
gated!(do_not_recommend, Normal, template!(Word), WarnFollowing, experimental!(do_not_recommend)),
+ // `#[cfi_encoding = ""]`
+ gated!(
+ cfi_encoding, Normal, template!(NameValueStr: "encoding"), ErrorPreceding,
+ experimental!(cfi_encoding)
+ ),
+
// ==========================================================================
// Internal attributes: Stability, deprecation, and unsafe:
// ==========================================================================
@@ -854,11 +861,11 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool {
/// Whether this builtin attribute is only used in the local crate.
/// If so, it is not encoded in the crate metadata.
pub fn is_builtin_only_local(name: Symbol) -> bool {
- BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| attr.only_local)
+ BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| attr.only_local)
}
pub fn is_valid_for_get_attr(name: Symbol) -> bool {
- BUILTIN_ATTRIBUTE_MAP.get(&name).map_or(false, |attr| match attr.duplicates {
+ BUILTIN_ATTRIBUTE_MAP.get(&name).is_some_and(|attr| match attr.duplicates {
WarnFollowing | ErrorFollowing | ErrorPreceding | FutureWarnFollowing
| FutureWarnPreceding => true,
DuplicatesOk | WarnFollowingWordOnly => false,
diff --git a/compiler/rustc_feature/src/lib.rs b/compiler/rustc_feature/src/lib.rs
index 3ce16e156..beb630784 100644
--- a/compiler/rustc_feature/src/lib.rs
+++ b/compiler/rustc_feature/src/lib.rs
@@ -84,14 +84,13 @@ impl UnstableFeatures {
pub fn from_environment(krate: Option<&str>) -> Self {
// `true` if this is a feature-staged build, i.e., on the beta or stable channel.
let disable_unstable_features =
- option_env!("CFG_DISABLE_UNSTABLE_FEATURES").map(|s| s != "0").unwrap_or(false);
+ option_env!("CFG_DISABLE_UNSTABLE_FEATURES").is_some_and(|s| s != "0");
// Returns whether `krate` should be counted as unstable
- let is_unstable_crate = |var: &str| {
- krate.map_or(false, |name| var.split(',').any(|new_krate| new_krate == name))
- };
+ let is_unstable_crate =
+ |var: &str| krate.is_some_and(|name| var.split(',').any(|new_krate| new_krate == name));
// `true` if we should enable unstable features for bootstrapping.
- let bootstrap = std::env::var("RUSTC_BOOTSTRAP")
- .map_or(false, |var| var == "1" || is_unstable_crate(&var));
+ let bootstrap =
+ std::env::var("RUSTC_BOOTSTRAP").is_ok_and(|var| var == "1" || is_unstable_crate(&var));
match (disable_unstable_features, bootstrap) {
(_, true) => UnstableFeatures::Cheat,
(true, _) => UnstableFeatures::Disallow,
diff --git a/compiler/rustc_feature/src/removed.rs b/compiler/rustc_feature/src/removed.rs
index aa51eaafd..8bca24b2b 100644
--- a/compiler/rustc_feature/src/removed.rs
+++ b/compiler/rustc_feature/src/removed.rs
@@ -139,7 +139,7 @@ declare_features! (
/// Allows using `#[on_unimplemented(..)]` on traits.
/// (Moved to `rustc_attrs`.)
(removed, on_unimplemented, "1.40.0", None, None, None),
- /// A way to temporarily opt out of opt in copy. This will *never* be accepted.
+ /// A way to temporarily opt out of opt-in copy. This will *never* be accepted.
(removed, opt_out_copy, "1.0.0", None, None, None),
/// Allows features specific to OIBIT (now called auto traits).
/// Renamed to `auto_traits`.
diff --git a/compiler/rustc_fluent_macro/Cargo.toml b/compiler/rustc_fluent_macro/Cargo.toml
new file mode 100644
index 000000000..f5a6585b5
--- /dev/null
+++ b/compiler/rustc_fluent_macro/Cargo.toml
@@ -0,0 +1,16 @@
+[package]
+name = "rustc_fluent_macro"
+version = "0.1.0"
+edition = "2021"
+
+[lib]
+proc-macro = true
+
+[dependencies]
+annotate-snippets = "0.9"
+fluent-bundle = "0.15.2"
+fluent-syntax = "0.11"
+syn = { version = "2", features = ["full"] }
+proc-macro2 = "1"
+quote = "1"
+unic-langid = { version = "0.9.0", features = ["macros"] }
diff --git a/compiler/rustc_macros/src/diagnostics/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs
index 607d51f56..9dffc9a76 100644
--- a/compiler/rustc_macros/src/diagnostics/fluent.rs
+++ b/compiler/rustc_fluent_macro/src/fluent.rs
@@ -68,7 +68,7 @@ fn failed(crate_name: &Ident) -> proc_macro::TokenStream {
.into()
}
-/// See [rustc_macros::fluent_messages].
+/// See [rustc_fluent_macro::fluent_messages].
pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
let crate_name = std::env::var("CARGO_PKG_NAME")
// If `CARGO_PKG_NAME` is missing, then we're probably running in a test, so use
diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs
new file mode 100644
index 000000000..a01643cd6
--- /dev/null
+++ b/compiler/rustc_fluent_macro/src/lib.rs
@@ -0,0 +1,64 @@
+#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(proc_macro_diagnostic)]
+#![feature(proc_macro_span)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
+#![allow(rustc::default_hash_types)]
+
+use proc_macro::TokenStream;
+
+mod fluent;
+
+/// Implements the `fluent_messages` macro, which performs compile-time validation of the
+/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same
+/// messages) and generates constants that make using those messages in diagnostics more ergonomic.
+///
+/// For example, given the following invocation of the macro..
+///
+/// ```ignore (rust)
+/// fluent_messages! { "./typeck.ftl" }
+/// ```
+/// ..where `typeck.ftl` has the following contents..
+///
+/// ```fluent
+/// typeck_field_multiply_specified_in_initializer =
+/// field `{$ident}` specified more than once
+/// .label = used more than once
+/// .label_previous_use = first use of `{$ident}`
+/// ```
+/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and
+/// will generate the following code:
+///
+/// ```ignore (rust)
+/// pub static DEFAULT_LOCALE_RESOURCE: &'static [&'static str] = include_str!("./typeck.ftl");
+///
+/// mod fluent_generated {
+/// mod typeck {
+/// pub const field_multiply_specified_in_initializer: DiagnosticMessage =
+/// DiagnosticMessage::fluent("typeck_field_multiply_specified_in_initializer");
+/// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage =
+/// DiagnosticMessage::fluent_attr(
+/// "typeck_field_multiply_specified_in_initializer",
+/// "previous_use_label"
+/// );
+/// }
+/// }
+/// ```
+/// When emitting a diagnostic, the generated constants can be used as follows:
+///
+/// ```ignore (rust)
+/// let mut err = sess.struct_span_err(
+/// span,
+/// fluent::typeck::field_multiply_specified_in_initializer
+/// );
+/// err.span_default_label(span);
+/// err.span_label(
+/// previous_use_span,
+/// fluent::typeck::field_multiply_specified_in_initializer_label_previous_use
+/// );
+/// err.emit();
+/// ```
+#[proc_macro]
+pub fn fluent_messages(input: TokenStream) -> TokenStream {
+ fluent::fluent_messages(input)
+}
diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs
index b70a55e89..5d86d8958 100644
--- a/compiler/rustc_graphviz/src/lib.rs
+++ b/compiler/rustc_graphviz/src/lib.rs
@@ -167,7 +167,7 @@
//! fn node_label(&self, n: &Nd) -> dot::LabelText<'_> {
//! dot::LabelText::LabelStr(self.nodes[*n].into())
//! }
-//! fn edge_label<'b>(&'b self, _: &Ed) -> dot::LabelText<'b> {
+//! fn edge_label(&self, _: &Ed<'_>) -> dot::LabelText<'_> {
//! dot::LabelText::LabelStr("&sube;".into())
//! }
//! }
@@ -177,8 +177,8 @@
//! type Edge = Ed<'a>;
//! fn nodes(&self) -> dot::Nodes<'a,Nd> { (0..self.nodes.len()).collect() }
//! fn edges(&'a self) -> dot::Edges<'a,Ed<'a>> { self.edges.iter().collect() }
-//! fn source(&self, e: &Ed) -> Nd { let & &(s,_) = e; s }
-//! fn target(&self, e: &Ed) -> Nd { let & &(_,t) = e; t }
+//! fn source(&self, e: &Ed<'_>) -> Nd { let & &(s,_) = e; s }
+//! fn target(&self, e: &Ed<'_>) -> Nd { let & &(_,t) = e; t }
//! }
//!
//! # pub fn main() { render_to(&mut Vec::new()) }
@@ -226,11 +226,11 @@
//! fn node_id(&'a self, n: &Nd<'a>) -> dot::Id<'a> {
//! dot::Id::new(format!("N{}", n.0)).unwrap()
//! }
-//! fn node_label<'b>(&'b self, n: &Nd<'b>) -> dot::LabelText<'b> {
+//! fn node_label(&self, n: &Nd<'_>) -> dot::LabelText<'_> {
//! let &(i, _) = n;
//! dot::LabelText::LabelStr(self.nodes[i].into())
//! }
-//! fn edge_label<'b>(&'b self, _: &Ed<'b>) -> dot::LabelText<'b> {
+//! fn edge_label(&self, _: &Ed<'_>) -> dot::LabelText<'_> {
//! dot::LabelText::LabelStr("&sube;".into())
//! }
//! }
diff --git a/compiler/rustc_hir/src/arena.rs b/compiler/rustc_hir/src/arena.rs
index c89e7eb75..e213623e0 100644
--- a/compiler/rustc_hir/src/arena.rs
+++ b/compiler/rustc_hir/src/arena.rs
@@ -1,56 +1,17 @@
/// This higher-order macro declares a list of types which can be allocated by `Arena`.
-///
-/// Specifying the `decode` modifier will add decode impls for `&T` and `&[T]`,
-/// where `T` is the type listed. These impls will appear in the implement_ty_decoder! macro.
+/// Note that all `Copy` types can be allocated by default and need not be specified here.
#[macro_export]
macro_rules! arena_types {
($macro:path) => (
$macro!([
// HIR types
[] hir_krate: rustc_hir::Crate<'tcx>,
- [] arm: rustc_hir::Arm<'tcx>,
- [] asm_operand: (rustc_hir::InlineAsmOperand<'tcx>, rustc_span::Span),
[] asm_template: rustc_ast::InlineAsmTemplatePiece,
[] attribute: rustc_ast::Attribute,
- [] closure: rustc_hir::Closure<'tcx>,
- [] block: rustc_hir::Block<'tcx>,
- [] bare_fn_ty: rustc_hir::BareFnTy<'tcx>,
- [] body: rustc_hir::Body<'tcx>,
- [] generics: rustc_hir::Generics<'tcx>,
- [] generic_arg: rustc_hir::GenericArg<'tcx>,
- [] generic_args: rustc_hir::GenericArgs<'tcx>,
- [] generic_bound: rustc_hir::GenericBound<'tcx>,
- [] generic_param: rustc_hir::GenericParam<'tcx>,
- [] expr: rustc_hir::Expr<'tcx>,
- [] impl_: rustc_hir::Impl<'tcx>,
- [] let_expr: rustc_hir::Let<'tcx>,
- [] expr_field: rustc_hir::ExprField<'tcx>,
- [] pat_field: rustc_hir::PatField<'tcx>,
- [] fn_decl: rustc_hir::FnDecl<'tcx>,
- [] foreign_item: rustc_hir::ForeignItem<'tcx>,
- [] foreign_item_ref: rustc_hir::ForeignItemRef,
- [] impl_item: rustc_hir::ImplItem<'tcx>,
- [] impl_item_ref: rustc_hir::ImplItemRef,
- [] item: rustc_hir::Item<'tcx>,
- [] inline_asm: rustc_hir::InlineAsm<'tcx>,
- [] local: rustc_hir::Local<'tcx>,
- [] mod_: rustc_hir::Mod<'tcx>,
[] owner_info: rustc_hir::OwnerInfo<'tcx>,
- [] param: rustc_hir::Param<'tcx>,
- [] pat: rustc_hir::Pat<'tcx>,
- [] path: rustc_hir::Path<'tcx>,
[] use_path: rustc_hir::UsePath<'tcx>,
- [] path_segment: rustc_hir::PathSegment<'tcx>,
- [] poly_trait_ref: rustc_hir::PolyTraitRef<'tcx>,
- [] qpath: rustc_hir::QPath<'tcx>,
- [] stmt: rustc_hir::Stmt<'tcx>,
- [] field_def: rustc_hir::FieldDef<'tcx>,
- [] trait_item: rustc_hir::TraitItem<'tcx>,
- [] trait_item_ref: rustc_hir::TraitItemRef,
- [] ty: rustc_hir::Ty<'tcx>,
- [] type_binding: rustc_hir::TypeBinding<'tcx>,
- [] variant: rustc_hir::Variant<'tcx>,
- [] where_predicate: rustc_hir::WherePredicate<'tcx>,
+ [] lit: rustc_hir::Lit,
+ [] macro_def: rustc_ast::MacroDef,
]);
)
}
diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs
index 8c58129c8..30bf8c2ad 100644
--- a/compiler/rustc_hir/src/def.rs
+++ b/compiler/rustc_hir/src/def.rs
@@ -234,10 +234,7 @@ impl DefKind {
#[inline]
pub fn is_fn_like(self) -> bool {
- match self {
- DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator => true,
- _ => false,
- }
+ matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Generator)
}
/// Whether `query get_codegen_attrs` should be used with this definition.
diff --git a/compiler/rustc_hir/src/definitions.rs b/compiler/rustc_hir/src/definitions.rs
index 8ceb17649..66b153d89 100644
--- a/compiler/rustc_hir/src/definitions.rs
+++ b/compiler/rustc_hir/src/definitions.rs
@@ -9,8 +9,8 @@ use crate::def_id::{CrateNum, DefIndex, LocalDefId, StableCrateId, CRATE_DEF_IND
use crate::def_path_hash_map::DefPathHashMap;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_index::vec::IndexVec;
+use rustc_data_structures::stable_hasher::{Hash64, StableHasher};
+use rustc_index::IndexVec;
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::{self, Write};
@@ -130,7 +130,7 @@ impl DefKey {
disambiguator.hash(&mut hasher);
- let local_hash: u64 = hasher.finish();
+ let local_hash = hasher.finish();
// Construct the new DefPathHash, making sure that the `crate_id`
// portion of the hash is properly copied from the parent. This way the
@@ -325,7 +325,7 @@ impl Definitions {
},
};
- let parent_hash = DefPathHash::new(stable_crate_id, 0);
+ let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO);
let def_path_hash = key.compute_stable_hash(parent_hash);
// Create the root definition.
diff --git a/compiler/rustc_hir/src/errors.rs b/compiler/rustc_hir/src/errors.rs
deleted file mode 100644
index e593ed104..000000000
--- a/compiler/rustc_hir/src/errors.rs
+++ /dev/null
@@ -1,10 +0,0 @@
-use crate::LangItem;
-
-#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, Encodable, Decodable)]
-pub struct LangItemError(pub LangItem);
-
-impl ToString for LangItemError {
- fn to_string(&self) -> String {
- format!("requires `{}` lang_item", self.0.name())
- }
-}
diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs
index 35a72f868..e84473109 100644
--- a/compiler/rustc_hir/src/hir.rs
+++ b/compiler/rustc_hir/src/hir.rs
@@ -14,7 +14,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::sorted_map::SortedMap;
use rustc_error_messages::MultiSpan;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::Spanned;
@@ -26,7 +26,7 @@ use rustc_target::spec::abi::Abi;
use smallvec::SmallVec;
use std::fmt;
-#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Lifetime {
pub hir_id: HirId,
@@ -41,8 +41,7 @@ pub struct Lifetime {
pub res: LifetimeName,
}
-#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
-#[derive(HashStable_Generic)]
+#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub enum ParamName {
/// Some user-given name like `T` or `'x`.
Plain(Ident),
@@ -85,8 +84,7 @@ impl ParamName {
}
}
-#[derive(Debug, Clone, PartialEq, Eq, Encodable, Hash, Copy)]
-#[derive(HashStable_Generic)]
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable_Generic)]
pub enum LifetimeName {
/// User-given names or fresh (synthetic) names.
Param(LocalDefId),
@@ -182,7 +180,7 @@ impl Lifetime {
/// A `Path` is essentially Rust's notion of a name; for instance,
/// `std::cmp::PartialEq`. It's represented as a sequence of identifiers,
/// along with a bunch of supporting information.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Path<'hir, R = Res> {
pub span: Span,
/// The resolution for the path.
@@ -202,7 +200,7 @@ impl Path<'_> {
/// A segment of a path: an identifier, an optional lifetime, and a set of
/// types.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PathSegment<'hir> {
/// The identifier portion of this path segment.
pub ident: Ident,
@@ -243,13 +241,13 @@ impl<'hir> PathSegment<'hir> {
}
}
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct ConstArg {
pub value: AnonConst,
pub span: Span,
}
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub struct InferArg {
pub hir_id: HirId,
pub span: Span,
@@ -261,7 +259,7 @@ impl InferArg {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericArg<'hir> {
Lifetime(&'hir Lifetime),
Type(&'hir Ty<'hir>),
@@ -318,7 +316,7 @@ impl GenericArg<'_> {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct GenericArgs<'hir> {
/// The generic arguments for this path segment.
pub args: &'hir [GenericArg<'hir>],
@@ -422,8 +420,7 @@ impl<'hir> GenericArgs<'hir> {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
pub enum GenericArgsParentheses {
No,
/// Bounds for `feature(return_type_notation)`, like `T: Trait<method(..): Send>`,
@@ -435,10 +432,10 @@ pub enum GenericArgsParentheses {
/// A modifier on a bound, currently this is only used for `?Sized`, where the
/// modifier is `Maybe`. Negative bounds should also be handled here.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
-#[derive(HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum TraitBoundModifier {
None,
+ Negative,
Maybe,
MaybeConst,
}
@@ -447,7 +444,7 @@ pub enum TraitBoundModifier {
/// `typeck::collect::compute_bounds` matches these against
/// the "special" built-in traits (see `middle::lang_items`) and
/// detects `Copy`, `Send` and `Sync`.
-#[derive(Clone, Debug, HashStable_Generic)]
+#[derive(Clone, Copy, Debug, HashStable_Generic)]
pub enum GenericBound<'hir> {
Trait(PolyTraitRef<'hir>, TraitBoundModifier),
// FIXME(davidtwco): Introduce `PolyTraitRef::LangItem`
@@ -474,7 +471,7 @@ impl GenericBound<'_> {
pub type GenericBounds<'hir> = &'hir [GenericBound<'hir>];
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum LifetimeParamKind {
// Indicates that the lifetime definition was explicitly declared (e.g., in
// `fn foo<'a>(x: &'a u8) -> &'a u8 { x }`).
@@ -488,7 +485,7 @@ pub enum LifetimeParamKind {
Error,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericParamKind<'hir> {
/// A lifetime definition (e.g., `'a: 'b + 'c + 'd`).
Lifetime {
@@ -505,7 +502,7 @@ pub enum GenericParamKind<'hir> {
},
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct GenericParam<'hir> {
pub hir_id: HirId,
pub def_id: LocalDefId,
@@ -539,7 +536,7 @@ impl<'hir> GenericParam<'hir> {
/// early-bound (but can be a late-bound lifetime in functions, for example),
/// or from a `for<...>` binder, in which case it's late-bound (and notably,
/// does not show up in the parent item's generics).
-#[derive(Debug, HashStable_Generic, PartialEq, Eq, Copy, Clone)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum GenericParamSource {
// Early or late-bound parameters defined on an item
Generics,
@@ -557,7 +554,7 @@ pub struct GenericParamCount {
/// Represents lifetimes and type parameters attached to a declaration
/// of a function, enum, trait, etc.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Generics<'hir> {
pub params: &'hir [GenericParam<'hir>],
pub predicates: &'hir [WherePredicate<'hir>],
@@ -729,7 +726,7 @@ impl<'hir> Generics<'hir> {
}
/// A single predicate in a where-clause.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum WherePredicate<'hir> {
/// A type binding (e.g., `for<'c> Foo: Send + Clone + 'c`).
BoundPredicate(WhereBoundPredicate<'hir>),
@@ -773,7 +770,7 @@ pub enum PredicateOrigin {
}
/// A type bound (e.g., `for<'c> Foo: Send + Clone + 'c`).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereBoundPredicate<'hir> {
pub hir_id: HirId,
pub span: Span,
@@ -790,12 +787,12 @@ pub struct WhereBoundPredicate<'hir> {
impl<'hir> WhereBoundPredicate<'hir> {
/// Returns `true` if `param_def_id` matches the `bounded_ty` of this predicate.
pub fn is_param_bound(&self, param_def_id: DefId) -> bool {
- self.bounded_ty.as_generic_param().map_or(false, |(def_id, _)| def_id == param_def_id)
+ self.bounded_ty.as_generic_param().is_some_and(|(def_id, _)| def_id == param_def_id)
}
}
/// A lifetime predicate (e.g., `'a: 'b + 'c`).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereRegionPredicate<'hir> {
pub span: Span,
pub in_where_clause: bool,
@@ -811,7 +808,7 @@ impl<'hir> WhereRegionPredicate<'hir> {
}
/// An equality predicate (e.g., `T = int`); currently unsupported.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct WhereEqPredicate<'hir> {
pub span: Span,
pub lhs_ty: &'hir Ty<'hir>,
@@ -821,7 +818,7 @@ pub struct WhereEqPredicate<'hir> {
/// HIR node coupled with its parent's id in the same HIR owner.
///
/// The parent is trash when the node is a HIR owner.
-#[derive(Clone, Debug)]
+#[derive(Clone, Copy, Debug)]
pub struct ParentedNode<'tcx> {
pub parent: ItemLocalId,
pub node: Node<'tcx>,
@@ -863,7 +860,7 @@ pub struct OwnerNodes<'tcx> {
impl<'tcx> OwnerNodes<'tcx> {
pub fn node(&self) -> OwnerNode<'tcx> {
- use rustc_index::vec::Idx;
+ use rustc_index::Idx;
let node = self.nodes[ItemLocalId::new(0)].as_ref().unwrap().node;
let node = node.as_owner().unwrap(); // Indexing must ensure it is an OwnerNode.
node
@@ -959,7 +956,7 @@ pub struct Crate<'hir> {
pub opt_hir_hash: Option<Fingerprint>,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Closure<'hir> {
pub def_id: LocalDefId,
pub binder: ClosureBinder,
@@ -978,7 +975,7 @@ pub struct Closure<'hir> {
/// A block of statements `{ .. }`, which may have a label (in this case the
/// `targeted_by_break` field will be `true`) and may be `unsafe` by means of
/// the `rules` being anything but `DefaultBlock`.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Block<'hir> {
/// Statements in a block.
pub stmts: &'hir [Stmt<'hir>],
@@ -1006,7 +1003,7 @@ impl<'hir> Block<'hir> {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Pat<'hir> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@@ -1085,7 +1082,7 @@ impl<'hir> Pat<'hir> {
/// Patterns like the fields of Foo `{ x, ref y, ref mut z }`
/// are treated the same as` x: x, y: ref y, z: ref mut z`,
/// except `is_shorthand` is true.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct PatField<'hir> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@@ -1097,7 +1094,7 @@ pub struct PatField<'hir> {
pub span: Span,
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum RangeEnd {
Included,
Excluded,
@@ -1141,7 +1138,7 @@ impl fmt::Debug for DotDotPos {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum PatKind<'hir> {
/// Represents a wildcard pattern (i.e., `_`).
Wild,
@@ -1197,7 +1194,7 @@ pub enum PatKind<'hir> {
Slice(&'hir [Pat<'hir>], Option<&'hir Pat<'hir>>, &'hir [Pat<'hir>]),
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum BinOpKind {
/// The `+` operator (addition).
Add,
@@ -1325,7 +1322,7 @@ impl Into<ast::BinOpKind> for BinOpKind {
pub type BinOp = Spanned<BinOpKind>;
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum UnOp {
/// The `*` operator (dereferencing).
Deref,
@@ -1351,7 +1348,7 @@ impl UnOp {
}
/// A statement.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Stmt<'hir> {
pub hir_id: HirId,
pub kind: StmtKind<'hir>,
@@ -1359,7 +1356,7 @@ pub struct Stmt<'hir> {
}
/// The contents of a statement.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum StmtKind<'hir> {
/// A local (`let`) binding.
Local(&'hir Local<'hir>),
@@ -1375,7 +1372,7 @@ pub enum StmtKind<'hir> {
}
/// Represents a `let` statement (i.e., `let <pat>:<ty> = <init>;`).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Local<'hir> {
pub pat: &'hir Pat<'hir>,
/// Type annotation, if any (otherwise the type will be inferred).
@@ -1393,7 +1390,7 @@ pub struct Local<'hir> {
/// Represents a single arm of a `match` expression, e.g.
/// `<pat> (if <guard>) => <body>`.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Arm<'hir> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@@ -1411,7 +1408,7 @@ pub struct Arm<'hir> {
///
/// In an if-let, imagine it as `if (let <pat> = <expr>) { ... }`; in a let-else, it is part of the
/// desugaring to if-let. Only let-else supports the type annotation at present.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Let<'hir> {
pub hir_id: HirId,
pub span: Span,
@@ -1420,7 +1417,7 @@ pub struct Let<'hir> {
pub init: &'hir Expr<'hir>,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Guard<'hir> {
If(&'hir Expr<'hir>),
IfLet(&'hir Let<'hir>),
@@ -1440,7 +1437,7 @@ impl<'hir> Guard<'hir> {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ExprField<'hir> {
#[stable_hasher(ignore)]
pub hir_id: HirId,
@@ -1450,19 +1447,19 @@ pub struct ExprField<'hir> {
pub is_shorthand: bool,
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum BlockCheckMode {
DefaultBlock,
UnsafeBlock(UnsafeSource),
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum UnsafeSource {
CompilerGenerated,
UserProvided,
}
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)]
pub struct BodyId {
pub hir_id: HirId,
}
@@ -1488,7 +1485,7 @@ pub struct BodyId {
///
/// All bodies have an **owner**, which can be accessed via the HIR
/// map using `body_owner_def_id()`.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Body<'hir> {
pub params: &'hir [Param<'hir>],
pub value: &'hir Expr<'hir>,
@@ -1506,7 +1503,7 @@ impl<'hir> Body<'hir> {
}
/// The type of source expression that caused this generator to be created.
-#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Debug, Copy, Hash)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub enum GeneratorKind {
/// An explicit `async` block or the body of an async function.
@@ -1539,7 +1536,7 @@ impl GeneratorKind {
///
/// This helps error messages but is also used to drive coercions in
/// type-checking (see #60424).
-#[derive(Clone, PartialEq, PartialOrd, Eq, Hash, Debug, Copy)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, Copy)]
#[derive(HashStable_Generic, Encodable, Decodable)]
pub enum AsyncGeneratorKind {
/// An explicit `async` block written by the user.
@@ -1649,7 +1646,7 @@ impl fmt::Display for ConstContext {
/// A literal.
pub type Lit = Spanned<LitKind>;
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum ArrayLen {
Infer(HirId, Span),
Body(AnonConst),
@@ -1671,7 +1668,7 @@ impl ArrayLen {
///
/// You can check if this anon const is a default in a const param
/// `const N: usize = { ... }` with `tcx.hir().opt_const_param_default_param_def_id(..)`
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub struct AnonConst {
pub hir_id: HirId,
pub def_id: LocalDefId,
@@ -1679,7 +1676,7 @@ pub struct AnonConst {
}
/// An expression.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Expr<'hir> {
pub hir_id: HirId,
pub kind: ExprKind<'hir>,
@@ -1715,6 +1712,7 @@ impl Expr<'_> {
ExprKind::Continue(..) => ExprPrecedence::Continue,
ExprKind::Ret(..) => ExprPrecedence::Ret,
ExprKind::InlineAsm(..) => ExprPrecedence::InlineAsm,
+ ExprKind::OffsetOf(..) => ExprPrecedence::OffsetOf,
ExprKind::Struct(..) => ExprPrecedence::Struct,
ExprKind::Repeat(..) => ExprPrecedence::Repeat,
ExprKind::Yield(..) => ExprPrecedence::Yield,
@@ -1774,6 +1772,7 @@ impl Expr<'_> {
| ExprKind::Loop(..)
| ExprKind::Assign(..)
| ExprKind::InlineAsm(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::AssignOp(..)
| ExprKind::Lit(_)
| ExprKind::ConstBlock(..)
@@ -1818,7 +1817,7 @@ impl Expr<'_> {
pub fn can_have_side_effects(&self) -> bool {
match self.peel_drop_temps().kind {
- ExprKind::Path(_) | ExprKind::Lit(_) => false,
+ ExprKind::Path(_) | ExprKind::Lit(_) | ExprKind::OffsetOf(..) => false,
ExprKind::Type(base, _)
| ExprKind::Unary(_, base)
| ExprKind::Field(base, _)
@@ -1920,7 +1919,7 @@ pub fn is_range_literal(expr: &Expr<'_>) -> bool {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ExprKind<'hir> {
/// Allow anonymous constants from an inline `const` block
ConstBlock(AnonConst),
@@ -1957,10 +1956,10 @@ pub enum ExprKind<'hir> {
/// A unary operation (e.g., `!x`, `*x`).
Unary(UnOp, &'hir Expr<'hir>),
/// A literal (e.g., `1`, `"foo"`).
- Lit(Lit),
+ Lit(&'hir Lit),
/// A cast (e.g., `foo as f64`).
Cast(&'hir Expr<'hir>, &'hir Ty<'hir>),
- /// A type reference (e.g., `Foo`).
+ /// A type ascription (e.g., `x: Foo`). See RFC 3307.
Type(&'hir Expr<'hir>, &'hir Ty<'hir>),
/// Wraps the expression in a terminating scope.
/// This makes it semantically equivalent to `{ let _t = expr; _t }`.
@@ -2022,6 +2021,9 @@ pub enum ExprKind<'hir> {
/// Inline assembly (from `asm!`), with its outputs and inputs.
InlineAsm(&'hir InlineAsm<'hir>),
+ /// Field offset (`offset_of!`)
+ OffsetOf(&'hir Ty<'hir>, &'hir [Ident]),
+
/// A struct or struct-like variant literal expression.
///
/// E.g., `Foo {x: 1, y: 2}`, or `Foo {x: 1, .. base}`,
@@ -2046,7 +2048,7 @@ pub enum ExprKind<'hir> {
/// To resolve the path to a `DefId`, call [`qpath_res`].
///
/// [`qpath_res`]: ../../rustc_middle/ty/struct.TypeckResults.html#method.qpath_res
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum QPath<'hir> {
/// Path to a definition, optionally "fully-qualified" with a `Self`
/// type, if the path points to an associated item in a trait.
@@ -2100,7 +2102,7 @@ impl<'hir> QPath<'hir> {
}
/// Hints at the original code for a let statement.
-#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum LocalSource {
/// A `match _ { .. }`.
Normal,
@@ -2153,7 +2155,7 @@ impl MatchSource {
}
/// The loop type that yielded an `ExprKind::Loop`.
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum LoopSource {
/// A `loop { .. }` loop.
Loop,
@@ -2173,7 +2175,7 @@ impl LoopSource {
}
}
-#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum LoopIdError {
OutsideLoopScope,
UnlabeledCfInWhileCondition,
@@ -2192,7 +2194,7 @@ impl fmt::Display for LoopIdError {
}
}
-#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub struct Destination {
/// This is `Some(_)` iff there is an explicit user-specified 'label
pub label: Option<Label>,
@@ -2203,7 +2205,7 @@ pub struct Destination {
}
/// The yield kind that caused an `ExprKind::Yield`.
-#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub enum YieldSource {
/// An `<expr>.await`.
Await { expr: Option<HirId> },
@@ -2238,7 +2240,7 @@ impl From<GeneratorKind> for YieldSource {
// N.B., if you change this, you'll probably want to change the corresponding
// type structure in middle/ty.rs as well.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct MutTy<'hir> {
pub ty: &'hir Ty<'hir>,
pub mutbl: Mutability,
@@ -2246,7 +2248,7 @@ pub struct MutTy<'hir> {
/// Represents a function's signature in a trait declaration,
/// trait implementation, or a free function.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct FnSig<'hir> {
pub header: FnHeader,
pub decl: &'hir FnDecl<'hir>,
@@ -2273,7 +2275,7 @@ impl TraitItemId {
/// possibly including a default implementation. A trait item is
/// either required (meaning it doesn't have an implementation, just a
/// signature) or provided (meaning it has a default implementation).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TraitItem<'hir> {
pub ident: Ident,
pub owner_id: OwnerId,
@@ -2322,7 +2324,7 @@ impl<'hir> TraitItem<'hir> {
}
/// Represents a trait method's body (or just argument names).
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TraitFn<'hir> {
/// No default body in the trait, just a signature.
Required(&'hir [Ident]),
@@ -2332,7 +2334,7 @@ pub enum TraitFn<'hir> {
}
/// Represents a trait method or associated constant or type
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TraitItemKind<'hir> {
/// An associated constant with an optional value (otherwise `impl`s must contain a value).
Const(&'hir Ty<'hir>, Option<BodyId>),
@@ -2360,7 +2362,7 @@ impl ImplItemId {
}
/// Represents anything within an `impl` block.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ImplItem<'hir> {
pub ident: Ident,
pub owner_id: OwnerId,
@@ -2410,7 +2412,7 @@ impl<'hir> ImplItem<'hir> {
}
/// Represents various kinds of content within an `impl`.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ImplItemKind<'hir> {
/// An associated constant of the given type, set to the constant result
/// of the expression.
@@ -2439,7 +2441,7 @@ pub const FN_OUTPUT_NAME: Symbol = sym::Output;
/// Binding(...),
/// }
/// ```
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TypeBinding<'hir> {
pub hir_id: HirId,
pub ident: Ident,
@@ -2448,7 +2450,7 @@ pub struct TypeBinding<'hir> {
pub span: Span,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum Term<'hir> {
Ty(&'hir Ty<'hir>),
Const(AnonConst),
@@ -2467,7 +2469,7 @@ impl<'hir> From<AnonConst> for Term<'hir> {
}
// Represents the two kinds of type bindings.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TypeBindingKind<'hir> {
/// E.g., `Foo<Bar: Send>`.
Constraint { bounds: &'hir [GenericBound<'hir>] },
@@ -2490,7 +2492,7 @@ impl TypeBinding<'_> {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Ty<'hir> {
pub hir_id: HirId,
pub kind: TyKind<'hir>,
@@ -2635,7 +2637,7 @@ impl PrimTy {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct BareFnTy<'hir> {
pub unsafety: Unsafety,
pub abi: Abi,
@@ -2644,7 +2646,7 @@ pub struct BareFnTy<'hir> {
pub param_names: &'hir [Ident],
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct OpaqueTy<'hir> {
pub generics: &'hir Generics<'hir>,
pub bounds: GenericBounds<'hir>,
@@ -2653,18 +2655,21 @@ pub struct OpaqueTy<'hir> {
}
/// From whence the opaque type came.
-#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, HashStable_Generic)]
pub enum OpaqueTyOrigin {
/// `-> impl Trait`
FnReturn(LocalDefId),
/// `async fn`
AsyncFn(LocalDefId),
/// type aliases: `type Foo = impl Trait;`
- TyAlias,
+ TyAlias {
+ /// associated types in impl blocks for traits.
+ in_assoc_ty: bool,
+ },
}
/// The various kinds of types recognized by the compiler.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum TyKind<'hir> {
/// A variable length slice (i.e., `[T]`).
Slice(&'hir Ty<'hir>),
@@ -2704,7 +2709,7 @@ pub enum TyKind<'hir> {
Err(rustc_span::ErrorGuaranteed),
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum InlineAsmOperand<'hir> {
In {
reg: InlineAsmRegOrRegClass,
@@ -2757,7 +2762,7 @@ impl<'hir> InlineAsmOperand<'hir> {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct InlineAsm<'hir> {
pub template: &'hir [InlineAsmTemplatePiece],
pub template_strs: &'hir [(Symbol, Option<Symbol>, Span)],
@@ -2767,7 +2772,7 @@ pub struct InlineAsm<'hir> {
}
/// Represents a parameter in a function header.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Param<'hir> {
pub hir_id: HirId,
pub pat: &'hir Pat<'hir>,
@@ -2776,7 +2781,7 @@ pub struct Param<'hir> {
}
/// Represents the header (not the body) of a function declaration.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct FnDecl<'hir> {
/// The types of the function's parameters.
///
@@ -2813,7 +2818,7 @@ impl ImplicitSelfKind {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Debug)]
#[derive(HashStable_Generic)]
pub enum IsAsync {
Async,
@@ -2826,7 +2831,7 @@ impl IsAsync {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, Encodable, Decodable, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug, Encodable, Decodable, HashStable_Generic)]
pub enum Defaultness {
Default { has_value: bool },
Final,
@@ -2849,7 +2854,7 @@ impl Defaultness {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum FnRetTy<'hir> {
/// Return type is not specified.
///
@@ -2882,13 +2887,13 @@ pub enum ClosureBinder {
For { span: Span },
}
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Mod<'hir> {
pub spans: ModSpans,
pub item_ids: &'hir [ItemId],
}
-#[derive(Copy, Clone, Debug, HashStable_Generic, Encodable)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub struct ModSpans {
/// A span from the first token past `{` to the last token until `}`.
/// For `mod foo;`, the inner span ranges from the first token
@@ -2897,12 +2902,12 @@ pub struct ModSpans {
pub inject_use_span: Span,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct EnumDef<'hir> {
pub variants: &'hir [Variant<'hir>],
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Variant<'hir> {
/// Name of the variant.
pub ident: Ident,
@@ -2917,7 +2922,7 @@ pub struct Variant<'hir> {
pub span: Span,
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum UseKind {
/// One import, e.g., `use foo::bar` or `use foo::bar as baz`.
/// Also produced for each element of a list `use`, e.g.
@@ -2939,7 +2944,7 @@ pub enum UseKind {
/// that the `ref_id` is for. Note that `ref_id`'s value is not the `HirId` of the
/// trait being referred to but just a unique `HirId` that serves as a key
/// within the resolution map.
-#[derive(Clone, Debug, HashStable_Generic)]
+#[derive(Clone, Debug, Copy, HashStable_Generic)]
pub struct TraitRef<'hir> {
pub path: &'hir Path<'hir>,
// Don't hash the `ref_id`. It is tracked via the thing it is used to access.
@@ -2958,7 +2963,7 @@ impl TraitRef<'_> {
}
}
-#[derive(Clone, Debug, HashStable_Generic)]
+#[derive(Clone, Debug, Copy, HashStable_Generic)]
pub struct PolyTraitRef<'hir> {
/// The `'a` in `for<'a> Foo<&'a T>`.
pub bound_generic_params: &'hir [GenericParam<'hir>],
@@ -2969,7 +2974,7 @@ pub struct PolyTraitRef<'hir> {
pub span: Span,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct FieldDef<'hir> {
pub span: Span,
pub vis_span: Span,
@@ -2988,7 +2993,7 @@ impl FieldDef<'_> {
}
/// Fields and constructor IDs of enum variants and structs.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum VariantData<'hir> {
/// A struct variant.
///
@@ -3058,7 +3063,7 @@ impl ItemId {
/// An item
///
/// The name might be a dummy name in case of anonymous items
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Item<'hir> {
pub ident: Ident,
pub owner_id: OwnerId,
@@ -3146,7 +3151,6 @@ impl<'hir> Item<'hir> {
(ty, gen)
}
- /// An opaque `impl Trait` type alias, e.g., `type Foo = impl Bar;`.
/// Expect an [`ItemKind::OpaqueTy`] or panic.
#[track_caller]
pub fn expect_opaque_ty(&self) -> &OpaqueTy<'hir> {
@@ -3168,7 +3172,6 @@ impl<'hir> Item<'hir> {
(data, gen)
}
- /// A union definition, e.g., `union Foo<A, B> {x: A, y: B}`.
/// Expect an [`ItemKind::Union`] or panic.
#[track_caller]
pub fn expect_union(&self) -> (&VariantData<'hir>, &'hir Generics<'hir>) {
@@ -3230,7 +3233,7 @@ impl fmt::Display for Unsafety {
}
}
-#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
+#[derive(Copy, Clone, PartialEq, Eq, Debug)]
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum Constness {
Const,
@@ -3246,7 +3249,7 @@ impl fmt::Display for Constness {
}
}
-#[derive(Copy, Clone, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, Debug, HashStable_Generic)]
pub struct FnHeader {
pub unsafety: Unsafety,
pub constness: Constness,
@@ -3268,7 +3271,7 @@ impl FnHeader {
}
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ItemKind<'hir> {
/// An `extern crate` item, with optional *original* crate name if the crate was renamed.
///
@@ -3289,7 +3292,7 @@ pub enum ItemKind<'hir> {
/// A function declaration.
Fn(FnSig<'hir>, &'hir Generics<'hir>, BodyId),
/// A MBE macro definition (`macro_rules!` or `macro`).
- Macro(ast::MacroDef, MacroKind),
+ Macro(&'hir ast::MacroDef, MacroKind),
/// A module.
Mod(&'hir Mod<'hir>),
/// An external module, e.g. `extern { .. }`.
@@ -3315,7 +3318,7 @@ pub enum ItemKind<'hir> {
Impl(&'hir Impl<'hir>),
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct Impl<'hir> {
pub unsafety: Unsafety,
pub polarity: ImplPolarity,
@@ -3378,7 +3381,7 @@ impl ItemKind<'_> {
/// type or method, and whether it is public). This allows other
/// passes to find the impl they want without loading the ID (which
/// means fewer edges in the incremental compilation graph).
-#[derive(Encodable, Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct TraitItemRef {
pub id: TraitItemId,
pub ident: Ident,
@@ -3392,7 +3395,7 @@ pub struct TraitItemRef {
/// type or method, and whether it is public). This allows other
/// passes to find the impl they want without loading the ID (which
/// means fewer edges in the incremental compilation graph).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ImplItemRef {
pub id: ImplItemId,
pub ident: Ident,
@@ -3402,7 +3405,7 @@ pub struct ImplItemRef {
pub trait_item_def_id: Option<DefId>,
}
-#[derive(Copy, Clone, PartialEq, Encodable, Debug, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Debug, HashStable_Generic)]
pub enum AssocItemKind {
Const,
Fn { has_self: bool },
@@ -3431,14 +3434,14 @@ impl ForeignItemId {
/// type or method, and whether it is public). This allows other
/// passes to find the impl they want without loading the ID (which
/// means fewer edges in the incremental compilation graph).
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ForeignItemRef {
pub id: ForeignItemId,
pub ident: Ident,
pub span: Span,
}
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub struct ForeignItem<'hir> {
pub ident: Ident,
pub kind: ForeignItemKind<'hir>,
@@ -3460,7 +3463,7 @@ impl ForeignItem<'_> {
}
/// An item within an `extern` block.
-#[derive(Debug, HashStable_Generic)]
+#[derive(Debug, Clone, Copy, HashStable_Generic)]
pub enum ForeignItemKind<'hir> {
/// A foreign function.
Fn(&'hir FnDecl<'hir>, &'hir [Ident], &'hir Generics<'hir>),
@@ -3471,7 +3474,7 @@ pub enum ForeignItemKind<'hir> {
}
/// A variable captured by a closure.
-#[derive(Debug, Copy, Clone, Encodable, HashStable_Generic)]
+#[derive(Debug, Copy, Clone, HashStable_Generic)]
pub struct Upvar {
/// First span where it is accessed (there can be multiple).
pub span: Span,
@@ -3480,7 +3483,7 @@ pub struct Upvar {
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
// has length > 0 if the trait is found through an chain of imports, starting with the
// import/use statement in the scope where the trait is used.
-#[derive(Encodable, Decodable, Debug, HashStable_Generic)]
+#[derive(Debug, Clone, HashStable_Generic)]
pub struct TraitCandidate {
pub def_id: DefId,
pub import_ids: SmallVec<[LocalDefId; 1]>,
@@ -3531,12 +3534,20 @@ impl<'hir> OwnerNode<'hir> {
pub fn body_id(&self) -> Option<BodyId> {
match self {
- OwnerNode::TraitItem(TraitItem {
- kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+ OwnerNode::Item(Item {
+ kind:
+ ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
..
})
- | OwnerNode::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
- | OwnerNode::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+ | OwnerNode::TraitItem(TraitItem {
+ kind:
+ TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)),
+ ..
+ })
+ | OwnerNode::ImplItem(ImplItem {
+ kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body),
+ ..
+ }) => Some(*body),
_ => None,
}
}
@@ -3731,12 +3742,27 @@ impl<'hir> Node<'hir> {
pub fn body_id(&self) -> Option<BodyId> {
match self {
- Node::TraitItem(TraitItem {
- kind: TraitItemKind::Fn(_, TraitFn::Provided(body_id)),
+ Node::Item(Item {
+ kind:
+ ItemKind::Static(_, _, body) | ItemKind::Const(_, body) | ItemKind::Fn(_, _, body),
..
})
- | Node::ImplItem(ImplItem { kind: ImplItemKind::Fn(_, body_id), .. })
- | Node::Item(Item { kind: ItemKind::Fn(.., body_id), .. }) => Some(*body_id),
+ | Node::TraitItem(TraitItem {
+ kind:
+ TraitItemKind::Fn(_, TraitFn::Provided(body)) | TraitItemKind::Const(_, Some(body)),
+ ..
+ })
+ | Node::ImplItem(ImplItem {
+ kind: ImplItemKind::Fn(_, body) | ImplItemKind::Const(_, body),
+ ..
+ })
+ | Node::Expr(Expr {
+ kind:
+ ExprKind::ConstBlock(AnonConst { body, .. })
+ | ExprKind::Closure(Closure { body, .. })
+ | ExprKind::Repeat(_, ArrayLen::Body(AnonConst { body, .. })),
+ ..
+ }) => Some(*body),
_ => None,
}
}
diff --git a/compiler/rustc_hir/src/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs
index 37ac37231..d549f52f8 100644
--- a/compiler/rustc_hir/src/hir_id.rs
+++ b/compiler/rustc_hir/src/hir_id.rs
@@ -35,7 +35,7 @@ impl OwnerId {
}
}
-impl rustc_index::vec::Idx for OwnerId {
+impl rustc_index::Idx for OwnerId {
#[inline]
fn new(idx: usize) -> Self {
OwnerId { def_id: LocalDefId { local_def_index: DefIndex::from_usize(idx) } }
@@ -116,10 +116,7 @@ impl HirId {
}
pub fn index(self) -> (usize, usize) {
- (
- rustc_index::vec::Idx::index(self.owner.def_id),
- rustc_index::vec::Idx::index(self.local_id),
- )
+ (rustc_index::Idx::index(self.owner.def_id), rustc_index::Idx::index(self.local_id))
}
}
diff --git a/compiler/rustc_hir/src/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs
index 234256ab5..df0047d82 100644
--- a/compiler/rustc_hir/src/intravisit.rs
+++ b/compiler/rustc_hir/src/intravisit.rs
@@ -786,6 +786,10 @@ pub fn walk_expr<'v, V: Visitor<'v>>(visitor: &mut V, expression: &'v Expr<'v>)
ExprKind::InlineAsm(ref asm) => {
visitor.visit_inline_asm(asm, expression.hir_id);
}
+ ExprKind::OffsetOf(ref container, ref fields) => {
+ visitor.visit_ty(container);
+ walk_list!(visitor, visit_ident, fields.iter().copied());
+ }
ExprKind::Yield(ref subexpression, _) => {
visitor.visit_expr(subexpression);
}
diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs
index 8f91a96f9..4b3bc816b 100644
--- a/compiler/rustc_hir/src/lang_items.rs
+++ b/compiler/rustc_hir/src/lang_items.rs
@@ -8,7 +8,6 @@
//! * Functions called by the compiler itself.
use crate::def_id::DefId;
-use crate::errors::LangItemError;
use crate::{MethodKind, Target};
use rustc_ast as ast;
@@ -42,13 +41,6 @@ impl LanguageItems {
self.items[item as usize] = Some(def_id);
}
- /// Requires that a given `LangItem` was bound and returns the corresponding `DefId`.
- /// If it wasn't bound, e.g. due to a missing `#[lang = "<it.name()>"]`,
- /// returns an error encapsulating the `LangItem`.
- pub fn require(&self, it: LangItem) -> Result<DefId, LangItemError> {
- self.get(it).ok_or_else(|| LangItemError(it))
- }
-
pub fn iter(&self) -> impl Iterator<Item = (LangItem, DefId)> + '_ {
self.items
.iter()
@@ -226,6 +218,7 @@ language_item_table! {
PartialEq, sym::eq, eq_trait, Target::Trait, GenericRequirement::Exact(1);
PartialOrd, sym::partial_ord, partial_ord_trait, Target::Trait, GenericRequirement::Exact(1);
+ CVoid, sym::c_void, c_void, Target::Enum, GenericRequirement::None;
// A number of panic-related lang items. The `panic` item corresponds to divide-by-zero and
// various panic cases with `match`. The `panic_bounds_check` item is for indexing arrays.
@@ -293,6 +286,8 @@ language_item_table! {
PointerLike, sym::pointer_like, pointer_like, Target::Trait, GenericRequirement::Exact(0);
+ ConstParamTy, sym::const_param_ty, const_param_ty_trait, Target::Trait, GenericRequirement::Exact(0);
+
Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None;
PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None;
PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None;
@@ -330,6 +325,7 @@ language_item_table! {
RangeTo, sym::RangeTo, range_to_struct, Target::Struct, GenericRequirement::None;
String, sym::String, string, Target::Struct, GenericRequirement::None;
+ CStr, sym::CStr, c_str, Target::Struct, GenericRequirement::None;
}
pub enum GenericRequirement {
diff --git a/compiler/rustc_hir/src/lib.rs b/compiler/rustc_hir/src/lib.rs
index 98d967cc0..616de57dc 100644
--- a/compiler/rustc_hir/src/lib.rs
+++ b/compiler/rustc_hir/src/lib.rs
@@ -30,7 +30,6 @@ pub mod def;
pub mod def_path_hash_map;
pub mod definitions;
pub mod diagnostic_items;
-pub mod errors;
pub use rustc_span::def_id;
mod hir;
pub mod hir_id;
diff --git a/compiler/rustc_hir/src/tests.rs b/compiler/rustc_hir/src/tests.rs
index d47911509..a40a01787 100644
--- a/compiler/rustc_hir/src/tests.rs
+++ b/compiler/rustc_hir/src/tests.rs
@@ -1,4 +1,5 @@
use crate::definitions::{DefKey, DefPathData, DisambiguatedDefPathData};
+use rustc_data_structures::stable_hasher::Hash64;
use rustc_span::def_id::{DefPathHash, StableCrateId};
use rustc_span::edition::Edition;
use rustc_span::{create_session_if_not_set_then, Symbol};
@@ -9,13 +10,13 @@ fn def_path_hash_depends_on_crate_id() {
// the crate-id of the defining crate. This is a desirable property
// because the crate-id can be more easily changed than the DefPath
// of an item, so, in the case of a crate-local DefPathHash collision,
- // the user can simply "role the dice again" for all DefPathHashes in
+ // the user can simply "roll the dice again" for all DefPathHashes in
// the crate by changing the crate disambiguator (e.g. via bumping the
// crate's version number).
create_session_if_not_set_then(Edition::Edition2024, |_| {
- let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()]);
- let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()]);
+ let id0 = StableCrateId::new(Symbol::intern("foo"), false, vec!["1".to_string()], "");
+ let id1 = StableCrateId::new(Symbol::intern("foo"), false, vec!["2".to_string()], "");
let h0 = mk_test_hash(id0);
let h1 = mk_test_hash(id1);
@@ -24,7 +25,7 @@ fn def_path_hash_depends_on_crate_id() {
assert_ne!(h0.local_hash(), h1.local_hash());
fn mk_test_hash(stable_crate_id: StableCrateId) -> DefPathHash {
- let parent_hash = DefPathHash::new(stable_crate_id, 0);
+ let parent_hash = DefPathHash::new(stable_crate_id, Hash64::ZERO);
let key = DefKey {
parent: None,
diff --git a/compiler/rustc_hir_analysis/Cargo.toml b/compiler/rustc_hir_analysis/Cargo.toml
index fab16b80f..4eb94d5bc 100644
--- a/compiler/rustc_hir_analysis/Cargo.toml
+++ b/compiler/rustc_hir_analysis/Cargo.toml
@@ -15,6 +15,7 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_session = { path = "../rustc_session" }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
@@ -23,8 +24,7 @@ rustc_span = { path = "../rustc_span" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
-rustc_lint = { path = "../rustc_lint" }
+rustc_lint_defs = { path = "../rustc_lint_defs" }
rustc_type_ir = { path = "../rustc_type_ir" }
rustc_feature = { path = "../rustc_feature" }
-thin-vec = "0.2.12"
tracing = "0.1"
diff --git a/compiler/rustc_hir_analysis/messages.ftl b/compiler/rustc_hir_analysis/messages.ftl
index 1d7965ff5..02d1dfcd1 100644
--- a/compiler/rustc_hir_analysis/messages.ftl
+++ b/compiler/rustc_hir_analysis/messages.ftl
@@ -1,73 +1,144 @@
-hir_analysis_unrecognized_atomic_operation =
- unrecognized atomic operation function: `{$op}`
- .label = unrecognized atomic operation
+hir_analysis_ambiguous_lifetime_bound =
+ ambiguous lifetime bound, explicit lifetime bound required
-hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
- intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
- .label = expected {$expected} {$descr} {$expected ->
- [one] parameter
- *[other] parameters
- }
+hir_analysis_assoc_type_binding_not_allowed =
+ associated type bindings are not allowed here
+ .label = associated type not allowed here
-hir_analysis_unrecognized_intrinsic_function =
- unrecognized intrinsic function: `{$name}`
- .label = unrecognized intrinsic
+hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
+ .suggestion = use a fully qualified path with inferred lifetimes
-hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
- lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
- .label = lifetimes do not match {$item_kind} in trait
- .generics_label = lifetimes in impl do not match this {$item_kind} in trait
- .where_label = this `where` clause might not match the one in the trait
- .bounds_label = this bound might be missing in the impl
+hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
hir_analysis_async_trait_impl_should_be_async =
method `{$method_name}` should be async because the method from the trait is async
.trait_item_label = required because the trait method is async
+hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
+ .label = deref recursion limit reached
+ .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+
+hir_analysis_cannot_capture_late_bound_const_in_anon_const =
+ cannot capture late-bound const parameter in a constant
+ .label = parameter defined here
+
+hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
+ cannot capture late-bound type parameter in a constant
+ .label = parameter defined here
+
+hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+
+hir_analysis_closure_implicit_hrtb = implicit types in closure signatures are forbidden when `for<...>` is present
+ .label = `for<...>` is here
+
+hir_analysis_const_bound_for_non_const_trait =
+ ~const can only be applied to `#[const_trait]` traits
+
+hir_analysis_const_impl_for_non_const_trait =
+ const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
+ .suggestion = mark `{$trait_name}` as const
+ .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
+ .adding = adding a non-const method body in the future would be a breaking change
+
+hir_analysis_const_param_ty_impl_on_non_adt =
+ the trait `ConstParamTy` may not be implemented for this type
+ .label = type is not a structure or enumeration
+
+hir_analysis_const_specialize = cannot specialize on const impl with non-const impl
+
+hir_analysis_copy_impl_on_non_adt =
+ the trait `Copy` cannot be implemented for this type
+ .label = type is not a structure or enumeration
+
+hir_analysis_copy_impl_on_type_with_dtor =
+ the trait `Copy` cannot be implemented for this type; the type has a destructor
+ .label = `Copy` not allowed on types with destructors
+
+hir_analysis_drop_impl_negative = negative `Drop` impls are not supported
+
hir_analysis_drop_impl_on_wrong_item =
the `Drop` trait may only be implemented for local structs, enums, and unions
.label = must be a struct, enum, or union in the current crate
+hir_analysis_drop_impl_reservation = reservation `Drop` impls are not supported
+
+hir_analysis_empty_specialization = specialization impl does not specialize any associated items
+ .note = impl is a specialization of this impl
+
+hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
+ .label = overflowed on value after {$discr}
+ .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
+
+hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+
hir_analysis_field_already_declared =
field `{$field_name}` is already declared
.label = field already declared
.previous_decl_label = `{$field_name}` first declared here
-hir_analysis_expected_used_symbol = expected `used`, `used(compiler)` or `used(linker)`
+hir_analysis_function_not_found_in_trait = function not found in this trait
-hir_analysis_ambiguous_lifetime_bound =
- ambiguous lifetime bound, explicit lifetime bound required
+hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
+ .note = required by this annotation
-hir_analysis_assoc_type_binding_not_allowed =
- associated type bindings are not allowed here
- .label = associated type not allowed here
+hir_analysis_functions_names_duplicated = functions names are duplicated
+ .note = all `#[rustc_must_implement_one_of]` arguments must be unique
-hir_analysis_parenthesized_fn_trait_expansion =
- parenthesized trait syntax expands to `{$expanded_type}`
+hir_analysis_impl_not_marked_default = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+ .label = cannot specialize default item `{$ident}`
+ .ok_label = parent `impl` is here
+ .note = to specialize, `{$ident}` in the parent `impl` must be marked `default`
-hir_analysis_typeof_reserved_keyword_used =
- `typeof` is a reserved keyword but unimplemented
- .suggestion = consider replacing `typeof(...)` with an actual type
- .label = reserved keyword
+hir_analysis_impl_not_marked_default_err = `{$ident}` specializes an item from a parent `impl`, but that item is not marked `default`
+ .note = parent implementation is in crate `{$cname}`
-hir_analysis_value_of_associated_struct_already_specified =
- the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
- .label = re-bound here
- .previous_bound_label = `{$item_name}` bound here first
+hir_analysis_invalid_union_field =
+ field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
+ .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
-hir_analysis_unconstrained_opaque_type = unconstrained opaque type
- .note = `{$name}` must be used in combination with a concrete type within the same {$what}
+hir_analysis_invalid_union_field_sugg =
+ wrap the field type in `ManuallyDrop<...>`
+
+hir_analysis_lifetimes_or_bounds_mismatch_on_trait =
+ lifetime parameters or bounds on {$item_kind} `{$ident}` do not match the trait declaration
+ .label = lifetimes do not match {$item_kind} in trait
+ .generics_label = lifetimes in impl do not match this {$item_kind} in trait
+ .where_label = this `where` clause might not match the one in the trait
+ .bounds_label = this bound might be missing in the impl
+
+hir_analysis_linkage_type =
+ invalid type for variable with `#[linkage]` attribute
+
+hir_analysis_main_function_async = `main` function is not allowed to be `async`
+ .label = `main` function is not allowed to be `async`
+
+hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters
+ .label = `main` cannot have generic parameters
+
+hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters
hir_analysis_manual_implementation =
manual implementations of `{$trait_name}` are experimental
.label = manual implementations of `{$trait_name}` are experimental
.help = add `#![feature(unboxed_closures)]` to the crate attributes to enable
-hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
+hir_analysis_missing_one_of_trait_item = not all trait items implemented, missing one of: `{$missing_items_msg}`
+ .label = missing one of `{$missing_items_msg}` in implementation
+ .note = required because of this annotation
-hir_analysis_trait_object_declared_with_no_traits =
- at least one trait is required for an object type
- .alias_span = this alias does not contain a trait
+hir_analysis_missing_tilde_const = missing `~const` qualifier for specialization
+
+hir_analysis_missing_trait_item = not all trait items implemented, missing: `{$missing_items_msg}`
+ .label = missing `{$missing_items_msg}` in implementation
+
+hir_analysis_missing_trait_item_label = `{$item}` from trait
+
+hir_analysis_missing_trait_item_suggestion = implement the missing item: `{$snippet}`
+
+hir_analysis_missing_trait_item_unstable = not all trait items implemented, missing: `{$missing_item_name}`
+ .note = default implementation of `{$missing_item_name}` is unstable
+ .some_note = use of unstable library feature '{$feature}': {$r}
+ .none_note = use of unstable library feature '{$feature}'
hir_analysis_missing_type_params =
the type {$parameterCount ->
@@ -91,137 +162,132 @@ hir_analysis_missing_type_params =
} to {$parameters}
.note = because of the default `Self` reference, type parameters must be specified on object types
-hir_analysis_copy_impl_on_type_with_dtor =
- the trait `Copy` cannot be implemented for this type; the type has a destructor
- .label = `Copy` not allowed on types with destructors
-
hir_analysis_multiple_relaxed_default_bounds =
type parameter has more than one relaxed default bound, only one is supported
-hir_analysis_copy_impl_on_non_adt =
- the trait `Copy` cannot be implemented for this type
- .label = type is not a structure or enumeration
-
-hir_analysis_const_impl_for_non_const_trait =
- const `impl` for trait `{$trait_name}` which is not marked with `#[const_trait]`
- .suggestion = mark `{$trait_name}` as const
- .note = marking a trait with `#[const_trait]` ensures all default method bodies are `const`
- .adding = adding a non-const method body in the future would be a breaking change
-
-hir_analysis_const_bound_for_non_const_trait =
- ~const can only be applied to `#[const_trait]` traits
-
-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_must_be_name_of_associated_function = must be a name of an associated function
-hir_analysis_linkage_type =
- invalid type for variable with `#[linkage]` attribute
+hir_analysis_must_implement_not_function = not a function
-hir_analysis_auto_deref_reached_recursion_limit = reached the recursion limit while auto-dereferencing `{$ty}`
- .label = deref recursion limit reached
- .help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
+hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
-hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
- .label = `main` cannot have a `where` clause
+hir_analysis_must_implement_not_function_span_note = required by this annotation
-hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
- .suggestion = remove this annotation
+hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
-hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
+hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
+ .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
-hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
- .label = `start` is not allowed to be `#[track_caller]`
+hir_analysis_parenthesized_fn_trait_expansion =
+ parenthesized trait syntax expands to `{$expanded_type}`
-hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]`
- .label = `start` is not allowed to have `#[target_feature]`
+hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
+ .suggestion = cast the value to `{$cast_ty}`
+ .help = cast the value to `{$cast_ty}`
-hir_analysis_start_not_async = `start` is not allowed to be `async`
- .label = `start` is not allowed to be `async`
+hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
+ .label = not allowed in type signatures
-hir_analysis_start_function_where = start function is not allowed to have a `where` clause
- .label = start function cannot have a `where` clause
+hir_analysis_return_type_notation_conflicting_bound =
+ ambiguous associated function `{$assoc_name}` for `{$ty_name}`
+ .note = `{$assoc_name}` is declared in two supertraits: `{$first_bound}` and `{$second_bound}`
-hir_analysis_start_function_parameters = start function is not allowed to have type parameters
- .label = start function cannot have type parameters
+hir_analysis_return_type_notation_equality_bound =
+ return type notation is not allowed to use type equality
-hir_analysis_main_function_return_type_generic = `main` function return type is not allowed to have generic parameters
+hir_analysis_return_type_notation_missing_method =
+ cannot find associated function `{$assoc_name}` for `{$ty_name}`
-hir_analysis_main_function_async = `main` function is not allowed to be `async`
- .label = `main` function is not allowed to be `async`
+hir_analysis_return_type_notation_on_non_rpitit =
+ return type notation used on function that is not `async` and does not return `impl Trait`
+ .note = function returns `{$ty}`, which is not compatible with associated type return bounds
+ .label = this function must be `async` or return `impl Trait`
-hir_analysis_main_function_generic_parameters = `main` function is not allowed to have generic parameters
- .label = `main` cannot have generic parameters
+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_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
- .label = C-variadic function must have a compatible calling convention
+hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
+ .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
-hir_analysis_cannot_capture_late_bound_ty_in_anon_const =
- cannot capture late-bound type parameter in a constant
- .label = parameter defined here
+hir_analysis_specialization_trait = implementing `rustc_specialization_trait` traits is unstable
+ .help = add `#![feature(min_specialization)]` to the crate attributes to enable
-hir_analysis_cannot_capture_late_bound_const_in_anon_const =
- cannot capture late-bound const parameter in a constant
- .label = parameter defined here
+hir_analysis_start_function_parameters = start function is not allowed to have type parameters
+ .label = start function cannot have type parameters
-hir_analysis_variances_of = {$variances_of}
+hir_analysis_start_function_where = start function is not allowed to have a `where` clause
+ .label = start function cannot have a `where` clause
-hir_analysis_pass_to_variadic_function = can't pass `{$ty}` to variadic function
- .suggestion = cast the value to `{$cast_ty}`
- .help = cast the value to `{$cast_ty}`
+hir_analysis_start_not_async = `start` is not allowed to be `async`
+ .label = `start` is not allowed to be `async`
-hir_analysis_cast_thin_pointer_to_fat_pointer = cannot cast thin pointer `{$expr_ty}` to fat pointer `{$cast_ty}`
+hir_analysis_start_not_target_feature = `start` is not allowed to have `#[target_feature]`
+ .label = `start` is not allowed to have `#[target_feature]`
-hir_analysis_invalid_union_field =
- field must implement `Copy` or be wrapped in `ManuallyDrop<...>` to be used in a union
- .note = union fields must not have drop side-effects, which is currently enforced via either `Copy` or `ManuallyDrop<...>`
+hir_analysis_start_not_track_caller = `start` is not allowed to be `#[track_caller]`
+ .label = `start` is not allowed to be `#[track_caller]`
-hir_analysis_invalid_union_field_sugg =
- wrap the field type in `ManuallyDrop<...>`
+hir_analysis_static_specialize = cannot specialize on `'static` lifetime
-hir_analysis_return_type_notation_on_non_rpitit =
- return type notation used on function that is not `async` and does not return `impl Trait`
- .note = function returns `{$ty}`, which is not compatible with associated type return bounds
- .label = this function must be `async` or return `impl Trait`
+hir_analysis_substs_on_overridden_impl = could not resolve substs on overridden impl
-hir_analysis_return_type_notation_equality_bound =
- return type notation is not allowed to use type equality
+hir_analysis_target_feature_on_main = `main` function is not allowed to have `#[target_feature]`
-hir_analysis_return_type_notation_missing_method =
- cannot find associated function `{$assoc_name}` in trait `{$trait_name}`
+hir_analysis_too_large_static = extern static is too large for the current architecture
-hir_analysis_placeholder_not_allowed_item_signatures = the placeholder `_` is not allowed within types on item signatures for {$kind}
- .label = not allowed in type signatures
+hir_analysis_track_caller_on_main = `main` function is not allowed to be `#[track_caller]`
+ .suggestion = remove this annotation
-hir_analysis_associated_type_trait_uninferred_generic_params = cannot use the associated type of a trait with uninferred generic parameters
- .suggestion = use a fully qualified path with inferred lifetimes
+hir_analysis_trait_object_declared_with_no_traits =
+ at least one trait is required for an object type
+ .alias_span = this alias does not contain a trait
-hir_analysis_associated_type_trait_uninferred_generic_params_multipart_suggestion = use a fully qualified path with explicit lifetimes
+hir_analysis_transparent_enum_variant = transparent enum needs exactly one variant, but has {$number}
+ .label = needs exactly one variant, but has {$number}
+ .many_label = too many variants in `{$path}`
+ .multi_label = variant here
-hir_analysis_enum_discriminant_overflowed = enum discriminant overflowed
- .label = overflowed on value after {$discr}
- .note = explicitly set `{$item_name} = {$wrapped_discr}` if that is desired outcome
+hir_analysis_transparent_non_zero_sized = transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+ .label = needs at most one non-zero-sized field, but has {$field_count}
+ .labels = this field is non-zero-sized
-hir_analysis_paren_sugar_attribute = the `#[rustc_paren_sugar]` attribute is a temporary means of controlling which traits can use parenthetical notation
- .help = add `#![feature(unboxed_closures)]` to the crate attributes to use it
+hir_analysis_transparent_non_zero_sized_enum = the variant of a transparent {$desc} needs at most one non-zero-sized field, but has {$field_count}
+ .label = needs at most one non-zero-sized field, but has {$field_count}
+ .labels = this field is non-zero-sized
-hir_analysis_must_implement_one_of_attribute = the `#[rustc_must_implement_one_of]` attribute must be used with at least 2 args
+hir_analysis_typeof_reserved_keyword_used =
+ `typeof` is a reserved keyword but unimplemented
+ .suggestion = consider replacing `typeof(...)` with an actual type
+ .label = reserved keyword
-hir_analysis_must_be_name_of_associated_function = must be a name of an associated function
+hir_analysis_unconstrained_opaque_type = unconstrained opaque type
+ .note = `{$name}` must be used in combination with a concrete type within the same {$what}
-hir_analysis_function_not_have_default_implementation = function doesn't have a default implementation
- .note = required by this annotation
+hir_analysis_unrecognized_atomic_operation =
+ unrecognized atomic operation function: `{$op}`
+ .label = unrecognized atomic operation
-hir_analysis_must_implement_not_function = not a function
+hir_analysis_unrecognized_intrinsic_function =
+ unrecognized intrinsic function: `{$name}`
+ .label = unrecognized intrinsic
-hir_analysis_must_implement_not_function_span_note = required by this annotation
+hir_analysis_value_of_associated_struct_already_specified =
+ the value of the associated type `{$item_name}` (from trait `{$def_path}`) is already specified
+ .label = re-bound here
+ .previous_bound_label = `{$item_name}` bound here first
-hir_analysis_must_implement_not_function_note = all `#[rustc_must_implement_one_of]` arguments must be associated function names
+hir_analysis_variadic_function_compatible_convention = C-variadic function must have a compatible calling convention, like {$conventions}
+ .label = C-variadic function must have a compatible calling convention
-hir_analysis_function_not_found_in_trait = function not found in this trait
+hir_analysis_variances_of = {$variances_of}
-hir_analysis_functions_names_duplicated = functions names are duplicated
- .note = all `#[rustc_must_implement_one_of]` arguments must be unique
+hir_analysis_where_clause_on_main = `main` function is not allowed to have a `where` clause
+ .label = `main` cannot have a `where` clause
-hir_analysis_simd_ffi_highly_experimental = use of SIMD type{$snip} in FFI is highly experimental and may result in invalid code
- .help = add `#![feature(simd_ffi)]` to the crate attributes to enable
+hir_analysis_wrong_number_of_generic_arguments_to_intrinsic =
+ intrinsic has wrong number of {$descr} parameters: found {$found}, expected {$expected}
+ .label = expected {$expected} {$descr} {$expected ->
+ [one] parameter
+ *[other] parameters
+ }
diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs
index 113c3f08a..7b922f5d5 100644
--- a/compiler/rustc_hir_analysis/src/astconv/errors.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs
@@ -243,13 +243,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let note = format!("{title} is defined in an impl for the type `{impl_ty}`");
if let Some(span) = note_span {
- err.span_note(span, &note);
+ err.span_note(span, note);
} else {
- err.note(&note);
+ err.note(note);
}
}
if candidates.len() > limit {
- err.note(&format!("and {} others", candidates.len() - limit));
+ err.note(format!("and {} others", candidates.len() - limit));
}
}
@@ -303,7 +303,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"associated type `{name}` not found for `{self_ty}` in the current scope"
);
err.span_label(name.span, format!("associated item not found in `{self_ty}`"));
- err.note(&format!(
+ err.note(format!(
"the associated type was found for\n{type_candidates}{additional_types}",
));
add_def_label(&mut err);
@@ -390,10 +390,10 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut err = tcx.sess.struct_span_err(
name.span,
- &format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
+ format!("the associated type `{name}` exists for `{self_ty}`, but its trait bounds were not satisfied")
);
if !bounds.is_empty() {
- err.note(&format!(
+ err.note(format!(
"the following trait bounds were not satisfied:\n{}",
bounds.join("\n")
));
@@ -409,7 +409,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if !tcx.sess.source_map().is_span_accessible(span) {
continue;
}
- err.span_label(span, &msg);
+ err.span_label(span, msg);
}
add_def_label(&mut err);
err.emit()
@@ -589,7 +589,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
if !suggestions.is_empty() {
err.multipart_suggestion(
- &format!("specify the associated type{}", pluralize!(types_count)),
+ format!("specify the associated type{}", pluralize!(types_count)),
suggestions,
Applicability::HasPlaceholders,
);
diff --git a/compiler/rustc_hir_analysis/src/astconv/generics.rs b/compiler/rustc_hir_analysis/src/astconv/generics.rs
index 3b5c67de2..39d1d1f2d 100644
--- a/compiler/rustc_hir_analysis/src/astconv/generics.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/generics.rs
@@ -24,7 +24,7 @@ fn generic_arg_mismatch_err(
arg: &GenericArg<'_>,
param: &GenericParamDef,
possible_ordering_error: bool,
- help: Option<&str>,
+ help: Option<String>,
) -> ErrorGuaranteed {
let sess = tcx.sess;
let mut err = struct_span_err!(
@@ -112,7 +112,7 @@ fn generic_arg_mismatch_err(
if let rustc_hir::ExprKind::Path(rustc_hir::QPath::Resolved(_, path)) = body.value.kind
{
if let Res::Def(DefKind::Fn { .. }, id) = path.res {
- err.help(&format!("`{}` is a function item, not a type", tcx.item_name(id)));
+ err.help(format!("`{}` is a function item, not a type", tcx.item_name(id)));
err.help("function item types cannot be named directly");
}
}
@@ -130,7 +130,7 @@ fn generic_arg_mismatch_err(
} else {
(arg.descr(), param.kind.descr())
};
- err.note(&format!("{} arguments must be provided before {} arguments", first, last));
+ err.note(format!("{} arguments must be provided before {} arguments", first, last));
if let Some(help) = help {
err.help(help);
}
@@ -300,7 +300,7 @@ pub fn create_substs_for_generic_args<'tcx, 'a>(
arg,
param,
!args_iter.clone().is_sorted_by_key(|arg| arg.to_ord()),
- Some(&format!(
+ Some(format!(
"reorder the arguments: {}: `<{}>`",
param_types_present
.into_iter()
diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs
index 8d1156c17..2c60a0624 100644
--- a/compiler/rustc_hir_analysis/src/astconv/mod.rs
+++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs
@@ -19,7 +19,7 @@ use rustc_ast::TraitObjectSyntax;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_errors::{
struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed, FatalError,
- MultiSpan,
+ MultiSpan, StashKey,
};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace, Res};
@@ -38,7 +38,6 @@ use rustc_middle::ty::{self, Const, IsSuggestable, Ty, TyCtxt, TypeVisitableExt}
use rustc_middle::ty::{DynKind, ToPredicate};
use rustc_session::lint::builtin::{AMBIGUOUS_ASSOCIATED_ITEMS, BARE_TRAIT_OBJECTS};
use rustc_span::edit_distance::find_best_match_for_name;
-use rustc_span::edition::Edition;
use rustc_span::symbol::{kw, Ident, Symbol};
use rustc_span::{sym, Span, DUMMY_SP};
use rustc_target::spec::abi;
@@ -56,6 +55,9 @@ use std::slice;
#[derive(Debug)]
pub struct PathSeg(pub DefId, pub usize);
+#[derive(Copy, Clone, Debug)]
+pub struct OnlySelfBounds(pub bool);
+
pub trait AstConv<'tcx> {
fn tcx(&self) -> TyCtxt<'tcx>;
@@ -447,14 +449,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
handle_ty_args(has_default, &inf.to_ty())
}
(GenericParamDefKind::Const { .. }, GenericArg::Const(ct)) => {
- ty::Const::from_opt_const_arg_anon_const(
- tcx,
- ty::WithOptConstParam {
- did: ct.value.def_id,
- const_param_did: Some(param.def_id),
- },
- )
- .into()
+ let did = ct.value.def_id;
+ tcx.feed_anon_const_type(did, tcx.type_of(param.def_id));
+ ty::Const::from_anon_const(tcx, did).into()
}
(&GenericParamDefKind::Const { .. }, hir::GenericArg::Infer(inf)) => {
let ty = tcx
@@ -466,7 +463,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.astconv.ct_infer(ty, Some(param), inf.span).into()
} else {
self.inferred_params.push(inf.span);
- tcx.const_error(ty).into()
+ tcx.const_error_misc(ty).into()
}
}
_ => unreachable!(),
@@ -520,7 +517,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.no_bound_vars()
.expect("const parameter types cannot be generic");
if let Err(guar) = ty.error_reported() {
- return tcx.const_error_with_guaranteed(ty, guar).into();
+ return tcx.const_error(ty, guar).into();
}
if !infer_args && has_default {
tcx.const_param_default(param.def_id).subst(tcx, substs.unwrap()).into()
@@ -529,7 +526,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.astconv.ct_infer(ty, Some(param), self.span).into()
} else {
// We've already errored above about the mismatch.
- tcx.const_error(ty).into()
+ tcx.const_error_misc(ty).into()
}
}
}
@@ -667,6 +664,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span: Span,
binding_span: Option<Span>,
constness: ty::BoundConstness,
+ polarity: ty::ImplPolarity,
bounds: &mut Bounds<'tcx>,
speculative: bool,
trait_ref_span: Span,
@@ -675,6 +673,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args: &GenericArgs<'_>,
infer_args: bool,
self_ty: Ty<'tcx>,
+ only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let (substs, arg_count) = self.create_substs_for_ast_path(
trait_ref_span,
@@ -694,13 +693,23 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let assoc_bindings = self.create_assoc_bindings_for_generic_args(args);
let poly_trait_ref =
- ty::Binder::bind_with_vars(tcx.mk_trait_ref(trait_def_id, substs), bound_vars);
+ ty::Binder::bind_with_vars(ty::TraitRef::new(tcx, trait_def_id, substs), bound_vars);
debug!(?poly_trait_ref, ?assoc_bindings);
- bounds.push_trait_bound(tcx, poly_trait_ref, span, constness);
+ bounds.push_trait_bound(tcx, poly_trait_ref, span, constness, polarity);
let mut dup_bindings = FxHashMap::default();
for binding in &assoc_bindings {
+ // Don't register additional associated type bounds for negative bounds,
+ // since we should have emitten an error for them earlier, and they will
+ // not be well-formed!
+ if polarity == ty::ImplPolarity::Negative {
+ self.tcx()
+ .sess
+ .delay_span_bug(binding.span, "negative trait bounds should not have bindings");
+ continue;
+ }
+
// Specify type to assert that error was already reported in `Err` case.
let _: Result<_, ErrorGuaranteed> = self.add_predicates_for_ast_type_binding(
hir_id,
@@ -711,6 +720,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&mut dup_bindings,
binding_span.unwrap_or(binding.span),
constness,
+ only_self_bounds,
+ polarity,
);
// Okay to ignore `Err` because of `ErrorGuaranteed` (see above).
}
@@ -743,9 +754,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
trait_ref: &hir::TraitRef<'_>,
span: Span,
constness: ty::BoundConstness,
+ polarity: ty::ImplPolarity,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
speculative: bool,
+ only_self_bounds: OnlySelfBounds,
) -> GenericArgCountResult {
let hir_id = trait_ref.hir_ref_id;
let binding_span = None;
@@ -763,6 +776,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
binding_span,
constness,
+ polarity,
bounds,
speculative,
trait_ref_span,
@@ -771,6 +785,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args,
infer_args,
self_ty,
+ only_self_bounds,
)
}
@@ -782,6 +797,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args: &GenericArgs<'_>,
self_ty: Ty<'tcx>,
bounds: &mut Bounds<'tcx>,
+ only_self_bounds: OnlySelfBounds,
) {
let binding_span = Some(span);
let constness = ty::BoundConstness::NotConst;
@@ -796,6 +812,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
span,
binding_span,
constness,
+ ty::ImplPolarity::Positive,
bounds,
speculative,
trait_ref_span,
@@ -804,6 +821,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
args,
infer_args,
self_ty,
+ only_self_bounds,
);
}
@@ -827,7 +845,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(b) = trait_segment.args().bindings.first() {
prohibit_assoc_ty_binding(self.tcx(), b.span, Some((trait_segment, span)));
}
- self.tcx().mk_trait_ref(trait_def_id, substs)
+ ty::TraitRef::new(self.tcx(), trait_def_id, substs)
}
#[instrument(level = "debug", skip(self, span))]
@@ -952,28 +970,43 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
ast_bounds: I,
bounds: &mut Bounds<'tcx>,
bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
+ only_self_bounds: OnlySelfBounds,
) {
for ast_bound in ast_bounds {
match ast_bound {
hir::GenericBound::Trait(poly_trait_ref, modifier) => {
- let constness = match modifier {
- hir::TraitBoundModifier::MaybeConst => ty::BoundConstness::ConstIfConst,
- hir::TraitBoundModifier::None => ty::BoundConstness::NotConst,
+ let (constness, polarity) = match modifier {
+ hir::TraitBoundModifier::MaybeConst => {
+ (ty::BoundConstness::ConstIfConst, ty::ImplPolarity::Positive)
+ }
+ hir::TraitBoundModifier::None => {
+ (ty::BoundConstness::NotConst, ty::ImplPolarity::Positive)
+ }
+ hir::TraitBoundModifier::Negative => {
+ (ty::BoundConstness::NotConst, ty::ImplPolarity::Negative)
+ }
hir::TraitBoundModifier::Maybe => continue,
};
-
let _ = self.instantiate_poly_trait_ref(
&poly_trait_ref.trait_ref,
poly_trait_ref.span,
constness,
+ polarity,
param_ty,
bounds,
false,
+ only_self_bounds,
);
}
&hir::GenericBound::LangItemTrait(lang_item, span, hir_id, args) => {
self.instantiate_lang_item_trait_ref(
- lang_item, span, hir_id, args, param_ty, bounds,
+ lang_item,
+ span,
+ hir_id,
+ args,
+ param_ty,
+ bounds,
+ only_self_bounds,
);
}
hir::GenericBound::Outlives(lifetime) => {
@@ -1011,13 +1044,24 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
+ only_self_bounds: OnlySelfBounds,
) -> Bounds<'tcx> {
- self.compute_bounds_inner(param_ty, ast_bounds)
+ let mut bounds = Bounds::default();
+ self.add_bounds(
+ param_ty,
+ ast_bounds.iter(),
+ &mut bounds,
+ ty::List::empty(),
+ only_self_bounds,
+ );
+ debug!(?bounds);
+
+ bounds
}
/// Convert the bounds in `ast_bounds` that refer to traits which define an associated type
/// named `assoc_name` into ty::Bounds. Ignore the rest.
- pub(crate) fn compute_bounds_that_match_assoc_type(
+ pub(crate) fn compute_bounds_that_match_assoc_item(
&self,
param_ty: Ty<'tcx>,
ast_bounds: &[hir::GenericBound<'_>],
@@ -1028,23 +1072,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
for ast_bound in ast_bounds {
if let Some(trait_ref) = ast_bound.trait_ref()
&& let Some(trait_did) = trait_ref.trait_def_id()
- && self.tcx().trait_may_define_assoc_type(trait_did, assoc_name)
+ && self.tcx().trait_may_define_assoc_item(trait_did, assoc_name)
{
result.push(ast_bound.clone());
}
}
- self.compute_bounds_inner(param_ty, &result)
- }
-
- fn compute_bounds_inner(
- &self,
- param_ty: Ty<'tcx>,
- ast_bounds: &[hir::GenericBound<'_>],
- ) -> Bounds<'tcx> {
let mut bounds = Bounds::default();
-
- self.add_bounds(param_ty, ast_bounds.iter(), &mut bounds, ty::List::empty());
+ self.add_bounds(
+ param_ty,
+ result.iter(),
+ &mut bounds,
+ ty::List::empty(),
+ OnlySelfBounds(true),
+ );
debug!(?bounds);
bounds
@@ -1067,6 +1108,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
dup_bindings: &mut FxHashMap<DefId, Span>,
path_span: Span,
constness: ty::BoundConstness,
+ only_self_bounds: OnlySelfBounds,
+ polarity: ty::ImplPolarity,
) -> Result<(), ErrorGuaranteed> {
// Given something like `U: SomeTrait<T = X>`, we want to produce a
// predicate like `<U as SomeTrait>::T = X`. This is somewhat
@@ -1097,11 +1140,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
) {
trait_ref
} else {
- return Err(tcx.sess.emit_err(crate::errors::ReturnTypeNotationMissingMethod {
- span: binding.span,
- trait_name: tcx.item_name(trait_ref.def_id()),
- assoc_name: binding.item_name.name,
- }));
+ self.one_bound_for_assoc_method(
+ traits::supertraits(tcx, trait_ref),
+ trait_ref.print_only_trait_path(),
+ binding.item_name,
+ path_span,
+ )?
}
} else if self.trait_defines_associated_item_named(
trait_ref.def_id(),
@@ -1115,7 +1159,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// those that do.
self.one_bound_for_assoc_type(
|| traits::supertraits(tcx, trait_ref),
- trait_ref.print_only_trait_path(),
+ trait_ref.skip_binder().print_only_trait_name(),
binding.item_name,
path_span,
match binding.kind {
@@ -1147,9 +1191,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
tcx.sess
.struct_span_err(
binding.span,
- &format!("{} `{}` is private", assoc_item.kind, binding.item_name),
+ format!("{} `{}` is private", assoc_item.kind, binding.item_name),
)
- .span_label(binding.span, &format!("private {}", assoc_item.kind))
+ .span_label(binding.span, format!("private {}", assoc_item.kind))
.emit();
}
tcx.check_stability(assoc_item.def_id, Some(hir_ref_id), binding.span, None);
@@ -1321,11 +1365,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let expected = tcx.def_descr(assoc_item_def_id);
let mut err = tcx.sess.struct_span_err(
binding.span,
- &format!("expected {expected} bound, found {got}"),
+ format!("expected {expected} bound, found {got}"),
);
err.span_note(
tcx.def_span(assoc_item_def_id),
- &format!("{expected} defined here"),
+ format!("{expected} defined here"),
);
if let hir::def::DefKind::AssocConst = def_kind
@@ -1342,7 +1386,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
term = match def_kind {
hir::def::DefKind::AssocTy => tcx.ty_error(reported).into(),
hir::def::DefKind::AssocConst => tcx
- .const_error_with_guaranteed(
+ .const_error(
tcx.type_of(assoc_item_def_id)
.subst(tcx, projection_ty.skip_binder().substs),
reported,
@@ -1366,8 +1410,20 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
//
// Calling `skip_binder` is okay, because `add_bounds` expects the `param_ty`
// parameter to have a skipped binder.
- let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
- self.add_bounds(param_ty, ast_bounds.iter(), bounds, projection_ty.bound_vars());
+ //
+ // NOTE: If `only_self_bounds` is true, do NOT expand this associated
+ // type bound into a trait predicate, since we only want to add predicates
+ // for the `Self` type.
+ if !only_self_bounds.0 {
+ let param_ty = tcx.mk_alias(ty::Projection, projection_ty.skip_binder());
+ self.add_bounds(
+ param_ty,
+ ast_bounds.iter(),
+ bounds,
+ projection_ty.bound_vars(),
+ only_self_bounds,
+ );
+ }
}
}
Ok(())
@@ -1405,9 +1461,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&trait_bound.trait_ref,
trait_bound.span,
ty::BoundConstness::NotConst,
+ ty::ImplPolarity::Positive,
dummy_self,
&mut bounds,
false,
+ // FIXME: This should be `true`, but we don't really handle
+ // associated type bounds or type aliases in objects in a way
+ // that makes this meaningful, I think.
+ OnlySelfBounds(false),
) {
potential_assoc_types.extend(cur_potential_assoc_types);
}
@@ -1471,7 +1532,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
"additional use",
);
first_trait.label_with_exp_info(&mut err, "first non-auto trait", "first use");
- err.help(&format!(
+ err.help(format!(
"consider creating a new trait with all of these as supertraits and using that \
trait here instead: `trait NewTrait: {} {{}}`",
regular_traits
@@ -1781,7 +1842,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
([], []) => {
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"if there were a type named `Type` that implements a trait named \
`Trait` with associated type `{name}`, you could use the \
fully-qualified path",
@@ -1793,7 +1854,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
([], [trait_str]) => {
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"if there were a type named `Example` that implemented `{trait_str}`, \
you could use the fully-qualified path",
),
@@ -1804,7 +1865,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
([], traits) => {
err.span_suggestions(
span,
- &format!(
+ format!(
"if there were a type named `Example` that implemented one of the \
traits with associated type `{name}`, you could use the \
fully-qualified path",
@@ -1819,7 +1880,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
([type_str], []) => {
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for `{type_str}`, you could use the fully-qualified path",
),
@@ -1830,7 +1891,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(types, []) => {
err.span_suggestions(
span,
- &format!(
+ format!(
"if there were a trait named `Example` with associated type `{name}` \
implemented for one of the types, you could use the fully-qualified \
path",
@@ -1885,7 +1946,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let param_name = tcx.hir().ty_param_name(ty_param_def_id);
self.one_bound_for_assoc_type(
|| {
- traits::transitive_bounds_that_define_assoc_type(
+ traits::transitive_bounds_that_define_assoc_item(
tcx,
predicates.iter().filter_map(|(p, _)| {
Some(p.to_opt_poly_trait_pred()?.map_bound(|t| t.trait_ref))
@@ -1996,7 +2057,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
);
}
} else {
- err.note(&format!(
+ err.note(format!(
"associated type `{}` could derive from `{}`",
ty_param_name,
bound.print_only_trait_path(),
@@ -2004,7 +2065,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
}
if !where_bounds.is_empty() {
- err.help(&format!(
+ err.help(format!(
"consider introducing a new type parameter `T` and adding `where` constraints:\
\n where\n T: {},\n{}",
ty_param_name,
@@ -2020,6 +2081,46 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
Ok(bound)
}
+ #[instrument(level = "debug", skip(self, all_candidates, ty_name), ret)]
+ fn one_bound_for_assoc_method(
+ &self,
+ all_candidates: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
+ ty_name: impl Display,
+ assoc_name: Ident,
+ span: Span,
+ ) -> Result<ty::PolyTraitRef<'tcx>, ErrorGuaranteed> {
+ let mut matching_candidates = all_candidates.filter(|r| {
+ self.trait_defines_associated_item_named(r.def_id(), ty::AssocKind::Fn, assoc_name)
+ });
+
+ let candidate = match matching_candidates.next() {
+ Some(candidate) => candidate,
+ None => {
+ return Err(self.tcx().sess.emit_err(
+ crate::errors::ReturnTypeNotationMissingMethod {
+ span,
+ ty_name: ty_name.to_string(),
+ assoc_name: assoc_name.name,
+ },
+ ));
+ }
+ };
+
+ if let Some(conflicting_candidate) = matching_candidates.next() {
+ return Err(self.tcx().sess.emit_err(
+ crate::errors::ReturnTypeNotationConflictingBound {
+ span,
+ ty_name: ty_name.to_string(),
+ assoc_name: assoc_name.name,
+ first_bound: candidate.print_only_trait_path(),
+ second_bound: conflicting_candidate.print_only_trait_path(),
+ },
+ ));
+ }
+
+ Ok(candidate)
+ }
+
// Create a type from a path to an associated type or to an enum variant.
// For a path `A::B::C::D`, `qself_ty` and `qself_def` are the type and def for `A::B::C`
// and item_segment is the path segment for `D`. We return a type and a def for
@@ -2061,7 +2162,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
err.note("enum variants can't have type parameters");
let type_name = tcx.item_name(adt_def.did());
let msg = format!(
- "you might have meant to specity type parameters on enum \
+ "you might have meant to specify type parameters on enum \
`{type_name}`"
);
let Some(args) = assoc_segment.args else { return; };
@@ -2072,14 +2173,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// work for the `enum`, instead of just looking if it takes *any*.
err.span_suggestion_verbose(
args_span,
- &format!("{type_name} doesn't have generic parameters"),
+ format!("{type_name} doesn't have generic parameters"),
"",
Applicability::MachineApplicable,
);
return;
}
let Ok(snippet) = tcx.sess.source_map().span_to_snippet(args_span) else {
- err.note(&msg);
+ err.note(msg);
return;
};
let (qself_sugg_span, is_self) = if let hir::TyKind::Path(
@@ -2113,12 +2214,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
kw::SelfUpper == segment.ident.name,
),
_ => {
- err.note(&msg);
+ err.note(msg);
return;
}
}
} else {
- err.note(&msg);
+ err.note(msg);
return;
};
let suggestion = vec![
@@ -2133,7 +2234,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
(args_span, String::new()),
];
err.multipart_suggestion_verbose(
- &msg,
+ msg,
suggestion,
Applicability::MaybeIncorrect,
);
@@ -2185,7 +2286,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let reported = if variant_resolution.is_some() {
// Variant in type position
let msg = format!("expected type, found variant `{}`", assoc_ident);
- tcx.sess.span_err(span, &msg)
+ tcx.sess.span_err(span, msg)
} else if qself_ty.is_enum() {
let mut err = struct_span_err!(
tcx.sess,
@@ -2256,7 +2357,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// Assume that if it's not matched, there must be a const defined with the same name
// but it was used in a type position.
let msg = format!("found associated const `{assoc_ident}` when type was expected");
- let guar = tcx.sess.struct_span_err(span, &msg).emit();
+ let guar = tcx.sess.struct_span_err(span, msg).emit();
return Err(guar);
};
@@ -2276,7 +2377,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
also,
tcx.def_kind_descr(kind, def_id)
);
- lint.span_note(tcx.def_span(def_id), &note_msg);
+ lint.span_note(tcx.def_span(def_id), note_msg);
};
could_refer_to(DefKind::Variant, variant_def_id, "");
@@ -2317,19 +2418,25 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
return Ok(None);
}
+ //
+ // Select applicable inherent associated type candidates modulo regions.
+ //
+
// In contexts that have no inference context, just make a new one.
// We do need a local variable to store it, though.
let infcx_;
let infcx = match self.infcx() {
Some(infcx) => infcx,
None => {
- assert!(!self_ty.needs_infer());
+ assert!(!self_ty.has_infer());
infcx_ = tcx.infer_ctxt().ignoring_regions().build();
&infcx_
}
};
- let param_env = tcx.param_env(block.owner.to_def_id());
+ // FIXME(inherent_associated_types): Acquiring the ParamEnv this early leads to cycle errors
+ // when inside of an ADT (#108491) or where clause.
+ let param_env = tcx.param_env(block.owner);
let cause = ObligationCause::misc(span, block.owner.def_id);
let mut fulfillment_errors = Vec::new();
@@ -2337,6 +2444,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let universe = infcx.create_next_universe();
// Regions are not considered during selection.
+ // FIXME(non_lifetime_binders): Here we are "truncating" or "flattening" the universes
+ // of type and const binders. Is that correct in the selection phase? See also #109505.
let self_ty = tcx.replace_escaping_bound_vars_uncached(
self_ty,
FnMutDelegate {
@@ -2352,41 +2461,40 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
candidates
.iter()
- .filter_map(|&(impl_, (assoc_item, def_scope))| {
+ .copied()
+ .filter(|&(impl_, _)| {
infcx.probe(|_| {
let ocx = ObligationCtxt::new_in_snapshot(&infcx);
- let impl_ty = tcx.type_of(impl_);
let impl_substs = infcx.fresh_item_substs(impl_);
- let impl_ty = impl_ty.subst(tcx, impl_substs);
+ let impl_ty = tcx.type_of(impl_).subst(tcx, impl_substs);
let impl_ty = ocx.normalize(&cause, param_env, impl_ty);
- // Check that the Self-types can be related.
- // FIXME(fmease): Should we use `eq` here?
- ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).ok()?;
+ // Check that the self types can be related.
+ // FIXME(inherent_associated_types): Should we use `eq` here? Method probing uses
+ // `sup` for this situtation, too. What for? To constrain inference variables?
+ if ocx.sup(&ObligationCause::dummy(), param_env, impl_ty, self_ty).is_err()
+ {
+ return false;
+ }
// Check whether the impl imposes obligations we have to worry about.
- let impl_bounds = tcx.predicates_of(impl_);
- let impl_bounds = impl_bounds.instantiate(tcx, impl_substs);
-
+ let impl_bounds = tcx.predicates_of(impl_).instantiate(tcx, impl_substs);
let impl_bounds = ocx.normalize(&cause, param_env, impl_bounds);
-
let impl_obligations = traits::predicates_for_generics(
|_, _| cause.clone(),
param_env,
impl_bounds,
);
-
ocx.register_obligations(impl_obligations);
let mut errors = ocx.select_where_possible();
if !errors.is_empty() {
fulfillment_errors.append(&mut errors);
- return None;
+ return false;
}
- // FIXME(fmease): Unsolved vars can escape this InferCtxt snapshot.
- Some((assoc_item, def_scope, infcx.resolve_vars_if_possible(impl_substs)))
+ true
})
})
.collect()
@@ -2395,24 +2503,26 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if applicable_candidates.len() > 1 {
return Err(self.complain_about_ambiguous_inherent_assoc_type(
name,
- applicable_candidates.into_iter().map(|(candidate, ..)| candidate).collect(),
+ applicable_candidates.into_iter().map(|(_, (candidate, _))| candidate).collect(),
span,
));
}
- if let Some((assoc_item, def_scope, impl_substs)) = applicable_candidates.pop() {
+ if let Some((impl_, (assoc_item, def_scope))) = applicable_candidates.pop() {
self.check_assoc_ty(assoc_item, name, def_scope, block, span);
- // FIXME(inherent_associated_types): To fully *confirm* the *probed* candidate, we still
- // need to relate the Self-type with fresh item substs & register region obligations for
- // regionck to prove/disprove.
-
- let item_substs =
- self.create_substs_for_associated_item(span, assoc_item, segment, impl_substs);
+ // FIXME(fmease): Currently creating throwaway `parent_substs` to please
+ // `create_substs_for_associated_item`. Modify the latter instead (or sth. similar) to
+ // not require the parent substs logic.
+ let parent_substs = InternalSubsts::identity_for_item(tcx, impl_);
+ let substs =
+ self.create_substs_for_associated_item(span, assoc_item, segment, parent_substs);
+ let substs = tcx.mk_substs_from_iter(
+ std::iter::once(ty::GenericArg::from(self_ty))
+ .chain(substs.into_iter().skip(parent_substs.len())),
+ );
- // FIXME(fmease, #106722): Check if the bounds on the parameters of the
- // associated type hold, if any.
- let ty = tcx.type_of(assoc_item).subst(tcx, item_substs);
+ let ty = tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(assoc_item, substs));
return Ok(Some((ty, assoc_item)));
}
@@ -2473,9 +2583,9 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let msg = format!("{kind} `{name}` is private");
let def_span = tcx.def_span(item);
tcx.sess
- .struct_span_err_with_code(span, &msg, rustc_errors::error_code!(E0624))
- .span_label(span, &format!("private {kind}"))
- .span_label(def_span, &format!("{kind} defined here"))
+ .struct_span_err_with_code(span, msg, rustc_errors::error_code!(E0624))
+ .span_label(span, format!("private {kind}"))
+ .span_label(def_span, format!("{kind} defined here"))
.emit();
}
tcx.check_stability(item, Some(block), span, None);
@@ -2494,7 +2604,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let infcx = if let Some(infcx) = self.infcx() {
infcx
} else {
- assert!(!qself_ty.needs_infer());
+ assert!(!qself_ty.has_infer());
infcx_ = tcx.infer_ctxt().build();
&infcx_
};
@@ -2515,7 +2625,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
&& tcx.all_impls(*trait_def_id)
.any(|impl_def_id| {
let trait_ref = tcx.impl_trait_ref(impl_def_id);
- trait_ref.map_or(false, |trait_ref| {
+ trait_ref.is_some_and(|trait_ref| {
let impl_ = trait_ref.subst(
tcx,
infcx.fresh_substs_for_item(DUMMY_SP, impl_def_id),
@@ -2923,7 +3033,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
self.prohibit_generics(path.segments.iter(), |err| {
if let Some(span) = tcx.def_ident_span(def_id) {
let name = tcx.item_name(def_id);
- err.span_note(span, &format!("type parameter `{name}` defined here"));
+ err.span_note(span, format!("type parameter `{name}` defined here"));
}
});
@@ -2984,7 +3094,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
let mut span: MultiSpan = vec![t_sp].into();
span.push_span_label(
i_sp,
- &format!("`Self` is on type `{type_name}` in this `impl`"),
+ format!("`Self` is on type `{type_name}` in this `impl`"),
);
let mut postfix = "";
if generics == 0 {
@@ -2992,11 +3102,11 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
span.push_span_label(
t_sp,
- &format!("`Self` corresponds to this type{postfix}"),
+ format!("`Self` corresponds to this type{postfix}"),
);
- err.span_note(span, &msg);
+ err.span_note(span, msg);
} else {
- err.note(&msg);
+ err.note(msg);
}
for segment in path.segments {
if let Some(args) = segment.args && segment.ident.name == kw::SelfUpper {
@@ -3044,7 +3154,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
// the anon const, which is empty. This is why the
// `AlwaysApplicable` impl needs a `T: ?Sized` bound for
// this to compile if we were to normalize here.
- if forbid_generic && ty.needs_subst() {
+ if forbid_generic && ty.has_param() {
let mut err = tcx.sess.struct_span_err(
path.span,
"generic `Self` types are currently not permitted in anonymous constants",
@@ -3087,7 +3197,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if let Some(args) = segment.args {
err.span_suggestion_verbose(
segment.ident.span.shrink_to_hi().to(args.span_ext),
- &format!("primitive type `{name}` doesn't have generic parameters"),
+ format!("primitive type `{name}` doesn't have generic parameters"),
"",
Applicability::MaybeIncorrect,
);
@@ -3378,7 +3488,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
if !infer_replacements.is_empty() {
diag.multipart_suggestion(
- &format!(
+ format!(
"try replacing `_` with the type{} in the corresponding trait method signature",
rustc_errors::pluralize!(infer_replacements.len()),
),
@@ -3544,7 +3654,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
..
}) = tcx.hir().get_by_def_id(parent_id) && self_ty.hir_id == impl_self_ty.hir_id
{
- if !of_trait_ref.trait_def_id().map_or(false, |def_id| def_id.is_local()) {
+ if !of_trait_ref.trait_def_id().is_some_and(|def_id| def_id.is_local()) {
return;
}
let of_trait_span = of_trait_ref.path.span;
@@ -3583,7 +3693,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
.source_map()
.span_to_prev_source(self_ty.span)
.ok()
- .map_or(false, |s| s.trim_end().ends_with('<'));
+ .is_some_and(|s| s.trim_end().ends_with('<'));
let is_global = poly_trait_ref.trait_ref.path.is_global();
@@ -3607,7 +3717,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
));
}
- if self_ty.span.edition() >= Edition::Edition2021 {
+ if self_ty.span.edition().rust_2021() {
let msg = "trait objects must include the `dyn` keyword";
let label = "add `dyn` keyword before this trait";
let mut diag =
@@ -3621,7 +3731,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o {
}
// check if the impl trait that we are considering is a impl of a local trait
self.maybe_lint_blanket_trait_impl(&self_ty, &mut diag);
- diag.emit();
+ diag.stash(self_ty.span, StashKey::TraitMissingMethod);
} else {
let msg = "trait objects without an explicit `dyn` are deprecated";
tcx.struct_span_lint_hir(
diff --git a/compiler/rustc_hir_analysis/src/autoderef.rs b/compiler/rustc_hir_analysis/src/autoderef.rs
index ba2d4319a..d6d1498d7 100644
--- a/compiler/rustc_hir_analysis/src/autoderef.rs
+++ b/compiler/rustc_hir_analysis/src/autoderef.rs
@@ -1,6 +1,5 @@
use crate::errors::AutoDerefReachedRecursionLimit;
use crate::traits::query::evaluate_obligation::InferCtxtExt;
-use crate::traits::NormalizeExt;
use crate::traits::{self, TraitEngine, TraitEngineExt};
use rustc_infer::infer::InferCtxt;
use rustc_middle::ty::TypeVisitableExt;
@@ -9,6 +8,7 @@ use rustc_session::Limit;
use rustc_span::def_id::LocalDefId;
use rustc_span::def_id::LOCAL_CRATE;
use rustc_span::Span;
+use rustc_trait_selection::traits::StructurallyNormalizeExt;
#[derive(Copy, Clone, Debug)]
pub enum AutoderefKind {
@@ -66,14 +66,27 @@ impl<'a, 'tcx> Iterator for Autoderef<'a, 'tcx> {
}
// Otherwise, deref if type is derefable:
- let (kind, new_ty) =
- if let Some(mt) = self.state.cur_ty.builtin_deref(self.include_raw_pointers) {
- (AutoderefKind::Builtin, mt.ty)
- } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
- (AutoderefKind::Overloaded, ty)
+ let (kind, new_ty) = if let Some(ty::TypeAndMut { ty, .. }) =
+ self.state.cur_ty.builtin_deref(self.include_raw_pointers)
+ {
+ debug_assert_eq!(ty, self.infcx.resolve_vars_if_possible(ty));
+ // NOTE: we may still need to normalize the built-in deref in case
+ // we have some type like `&<Ty as Trait>::Assoc`, since users of
+ // autoderef expect this type to have been structurally normalized.
+ if self.infcx.tcx.trait_solver_next()
+ && let ty::Alias(ty::Projection, _) = ty.kind()
+ {
+ let (normalized_ty, obligations) = self.structurally_normalize(ty)?;
+ self.state.obligations.extend(obligations);
+ (AutoderefKind::Builtin, normalized_ty)
} else {
- return None;
- };
+ (AutoderefKind::Builtin, ty)
+ }
+ } else if let Some(ty) = self.overloaded_deref_ty(self.state.cur_ty) {
+ (AutoderefKind::Overloaded, ty)
+ } else {
+ return None;
+ };
if new_ty.references_error() {
return None;
@@ -119,14 +132,11 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
fn overloaded_deref_ty(&mut self, ty: Ty<'tcx>) -> Option<Ty<'tcx>> {
debug!("overloaded_deref_ty({:?})", ty);
-
let tcx = self.infcx.tcx;
// <ty as Deref>
- let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]);
-
+ let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let cause = traits::ObligationCause::misc(self.span, self.body_id);
-
let obligation = traits::Obligation::new(
tcx,
cause.clone(),
@@ -138,26 +148,48 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> {
return None;
}
- let normalized_ty = self
+ let (normalized_ty, obligations) =
+ self.structurally_normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, [ty]))?;
+ debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
+ self.state.obligations.extend(obligations);
+
+ Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ }
+
+ #[instrument(level = "debug", skip(self), ret)]
+ pub fn structurally_normalize(
+ &self,
+ ty: Ty<'tcx>,
+ ) -> Option<(Ty<'tcx>, Vec<traits::PredicateObligation<'tcx>>)> {
+ let tcx = self.infcx.tcx;
+ let mut fulfill_cx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
+
+ let cause = traits::ObligationCause::misc(self.span, self.body_id);
+ let normalized_ty = match self
.infcx
.at(&cause, self.param_env)
- .normalize(tcx.mk_projection(tcx.lang_items().deref_target()?, trait_ref.substs));
- let mut fulfillcx = <dyn TraitEngine<'tcx>>::new_in_snapshot(tcx);
- let normalized_ty =
- normalized_ty.into_value_registering_obligations(self.infcx, &mut *fulfillcx);
- let errors = fulfillcx.select_where_possible(&self.infcx);
+ .structurally_normalize(ty, &mut *fulfill_cx)
+ {
+ Ok(normalized_ty) => normalized_ty,
+ Err(errors) => {
+ // This shouldn't happen, except for evaluate/fulfill mismatches,
+ // but that's not a reason for an ICE (`predicate_may_hold` is conservative
+ // by design).
+ debug!(?errors, "encountered errors while fulfilling");
+ return None;
+ }
+ };
+
+ let errors = fulfill_cx.select_where_possible(&self.infcx);
if !errors.is_empty() {
// This shouldn't happen, except for evaluate/fulfill mismatches,
// but that's not a reason for an ICE (`predicate_may_hold` is conservative
// by design).
- debug!("overloaded_deref_ty: encountered errors {:?} while fulfilling", errors);
+ debug!(?errors, "encountered errors while fulfilling");
return None;
}
- let obligations = fulfillcx.pending_obligations();
- debug!("overloaded_deref_ty({:?}) = ({:?}, {:?})", ty, normalized_ty, obligations);
- self.state.obligations.extend(obligations);
- Some(self.infcx.resolve_vars_if_possible(normalized_ty))
+ Some((normalized_ty, fulfill_cx.pending_obligations()))
}
/// Returns the final type we ended up with, which may be an inference
diff --git a/compiler/rustc_hir_analysis/src/bounds.rs b/compiler/rustc_hir_analysis/src/bounds.rs
index 284b099e7..686066abb 100644
--- a/compiler/rustc_hir_analysis/src/bounds.rs
+++ b/compiler/rustc_hir_analysis/src/bounds.rs
@@ -42,8 +42,14 @@ impl<'tcx> Bounds<'tcx> {
trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
constness: ty::BoundConstness,
+ polarity: ty::ImplPolarity,
) {
- self.predicates.push((trait_ref.with_constness(constness).to_predicate(tcx), span));
+ self.predicates.push((
+ trait_ref
+ .map_bound(|trait_ref| ty::TraitPredicate { trait_ref, constness, polarity })
+ .to_predicate(tcx),
+ span,
+ ));
}
pub fn push_projection_bound(
@@ -57,7 +63,7 @@ impl<'tcx> Bounds<'tcx> {
pub fn push_sized(&mut self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span) {
let sized_def_id = tcx.require_lang_item(LangItem::Sized, Some(span));
- let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [ty]));
+ let trait_ref = ty::TraitRef::new(tcx, sized_def_id, [ty]);
// Preferable to put this obligation first, since we report better errors for sized ambiguity.
self.predicates.insert(0, (trait_ref.without_const().to_predicate(tcx), span));
}
diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs
index 0bb98fdf2..3b2c052e8 100644
--- a/compiler/rustc_hir_analysis/src/check/check.rs
+++ b/compiler/rustc_hir_analysis/src/check/check.rs
@@ -13,11 +13,12 @@ use rustc_hir::intravisit::Visitor;
use rustc_hir::{ItemKind, Node, PathSegment};
use rustc_infer::infer::opaque_types::ConstrainOpaqueTypeRegionVisitor;
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
-use rustc_infer::infer::{DefiningAnchor, RegionVariableOrigin, TyCtxtInferExt};
+use rustc_infer::infer::{RegionVariableOrigin, TyCtxtInferExt};
use rustc_infer::traits::{Obligation, TraitEngineExt as _};
-use rustc_lint::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
+use rustc_lint_defs::builtin::REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::stability::EvalResult;
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::layout::{LayoutError, MAX_SIMD_LANES};
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::util::{Discr, IntTypeExt};
@@ -31,6 +32,7 @@ use rustc_target::abi::FieldIdx;
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::outlives_bounds::InferCtxtExt as _;
use rustc_trait_selection::traits::{self, ObligationCtxt, TraitEngine, TraitEngineExt as _};
use std::ops::ControlFlow;
@@ -170,14 +172,12 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) {
if matches!(tcx.def_kind(def_id), DefKind::Static(_)
if tcx.def_kind(tcx.local_parent(def_id)) == DefKind::ForeignMod) =>
{
- tcx.sess
- .struct_span_err(span, "extern static is too large for the current architecture")
- .emit();
+ tcx.sess.emit_err(errors::TooLargeStatic { span });
return;
}
// Generic statics are rejected, but we still reach this case.
Err(e) => {
- tcx.sess.delay_span_bug(span, &e.to_string());
+ tcx.sess.delay_span_bug(span, e.to_string());
return;
}
};
@@ -224,7 +224,7 @@ fn check_opaque(tcx: TyCtxt<'_>, id: hir::ItemId) {
if check_opaque_for_cycles(tcx, item.owner_id.def_id, substs, span, &origin).is_err() {
return;
}
- check_opaque_meets_bounds(tcx, item.owner_id.def_id, substs, span, &origin);
+ check_opaque_meets_bounds(tcx, item.owner_id.def_id, span, &origin);
}
/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result
@@ -320,7 +320,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
};
let prohibit_opaque = tcx
.explicit_item_bounds(def_id)
- .iter()
+ .subst_identity_iter_copied()
.try_for_each(|(predicate, _)| predicate.visit_with(&mut visitor));
if let Some(ty) = prohibit_opaque.break_value() {
@@ -336,7 +336,7 @@ pub(super) fn check_opaque_for_inheriting_lifetimes(
&tcx.sess.parse_sess,
sym::impl_trait_projections,
span,
- &format!(
+ format!(
"`{}` return type cannot contain a projection or `Self` that references \
lifetimes from a parent scope",
if is_async { "async fn" } else { "impl Trait" },
@@ -393,13 +393,12 @@ pub(super) fn check_opaque_for_cycles<'tcx>(
fn check_opaque_meets_bounds<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
- substs: SubstsRef<'tcx>,
span: Span,
origin: &hir::OpaqueTyOrigin,
) {
let defining_use_anchor = match *origin {
hir::OpaqueTyOrigin::FnReturn(did) | hir::OpaqueTyOrigin::AsyncFn(did) => did,
- hir::OpaqueTyOrigin::TyAlias => def_id,
+ hir::OpaqueTyOrigin::TyAlias { .. } => tcx.impl_trait_parent(def_id),
};
let param_env = tcx.param_env(defining_use_anchor);
@@ -408,6 +407,8 @@ fn check_opaque_meets_bounds<'tcx>(
.with_opaque_type_inference(DefiningAnchor::Bind(defining_use_anchor))
.build();
let ocx = ObligationCtxt::new(&infcx);
+
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
let opaque_ty = tcx.mk_opaque(def_id.to_def_id(), substs);
// `ReErased` regions appear in the "parent_substs" of closures/generators.
@@ -430,7 +431,7 @@ fn check_opaque_meets_bounds<'tcx>(
let ty_err = ty_err.to_string(tcx);
tcx.sess.delay_span_bug(
span,
- &format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
+ format!("could not unify `{hidden_ty}` with revealed type:\n{ty_err}"),
);
}
}
@@ -450,9 +451,18 @@ fn check_opaque_meets_bounds<'tcx>(
match origin {
// Checked when type checking the function containing them.
hir::OpaqueTyOrigin::FnReturn(..) | hir::OpaqueTyOrigin::AsyncFn(..) => {}
+ // Nested opaque types occur only in associated types:
+ // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
+ // They can only be referenced as `<Opaque<T> as Trait<&'static T>>::AssocTy`.
+ // We don't have to check them here because their well-formedness follows from the WF of
+ // the projection input types in the defining- and use-sites.
+ hir::OpaqueTyOrigin::TyAlias { .. }
+ if tcx.def_kind(tcx.parent(def_id.to_def_id())) == DefKind::OpaqueTy => {}
// Can have different predicates to their defining use
- hir::OpaqueTyOrigin::TyAlias => {
- let outlives_env = OutlivesEnvironment::new(param_env);
+ hir::OpaqueTyOrigin::TyAlias { .. } => {
+ let wf_tys = ocx.assumed_wf_types(param_env, span, def_id);
+ let implied_bounds = infcx.implied_bounds_tys(param_env, def_id, wf_tys);
+ let outlives_env = OutlivesEnvironment::with_bounds(param_env, implied_bounds);
let _ = ocx.resolve_regions_and_report_errors(defining_use_anchor, &outlives_env);
}
}
@@ -494,7 +504,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
debug!(
"check_item_type(it.def_id={:?}, it.name={})",
id.owner_id,
- tcx.def_path_str(id.owner_id.to_def_id())
+ tcx.def_path_str(id.owner_id)
);
let _indenter = indenter();
match tcx.def_kind(id.owner_id) {
@@ -538,7 +548,7 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
tcx,
assoc_item,
assoc_item,
- tcx.mk_trait_ref(id.owner_id.to_def_id(), trait_substs),
+ ty::TraitRef::new(tcx, id.owner_id.to_def_id(), trait_substs),
);
}
_ => {}
@@ -620,11 +630,11 @@ fn check_item_type(tcx: TyCtxt<'_>, id: hir::ItemId) {
E0044,
"foreign items may not have {kinds} parameters",
)
- .span_label(item.span, &format!("can't have {kinds} parameters"))
+ .span_label(item.span, format!("can't have {kinds} parameters"))
.help(
// FIXME: once we start storing spans for type arguments, turn this
// into a suggestion.
- &format!(
+ format!(
"replace the {} parameters with concrete {}{}",
kinds,
kinds_pl,
@@ -791,16 +801,15 @@ fn check_impl_items_against_trait<'tcx>(
let is_implemented = leaf_def
.as_ref()
- .map_or(false, |node_item| node_item.item.defaultness(tcx).has_value());
+ .is_some_and(|node_item| node_item.item.defaultness(tcx).has_value());
if !is_implemented && tcx.impl_defaultness(impl_id).is_final() {
missing_items.push(tcx.associated_item(trait_item_id));
}
// true if this item is specifically implemented in this impl
- let is_implemented_here = leaf_def
- .as_ref()
- .map_or(false, |node_item| !node_item.defining_node.is_from_trait());
+ let is_implemented_here =
+ leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait());
if !is_implemented_here {
let full_impl_span =
@@ -863,7 +872,7 @@ fn check_impl_items_against_trait<'tcx>(
if !missing_items.is_empty() {
let full_impl_span =
tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id));
- missing_items_err(tcx, tcx.def_span(impl_id), &missing_items, full_impl_span);
+ missing_items_err(tcx, impl_id, &missing_items, full_impl_span);
}
if let Some(missing_items) = must_implement_one_of {
@@ -987,10 +996,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
err.span_note(
tcx.def_span(def_spans[0].0),
- &format!(
- "`{}` has a `#[repr(align)]` attribute",
- tcx.item_name(def_spans[0].0)
- ),
+ format!("`{}` has a `#[repr(align)]` attribute", tcx.item_name(def_spans[0].0)),
);
if def_spans.len() > 2 {
@@ -999,7 +1005,7 @@ pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: ty::AdtDef<'_>) {
let ident = tcx.item_name(*adt_def);
err.span_note(
*span,
- &if first {
+ if first {
format!(
"`{}` contains a field of type `{}`",
tcx.type_of(def.did()).subst_identity(),
@@ -1076,8 +1082,8 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>)
let layout = tcx.layout_of(param_env.and(ty));
// We are currently checking the type this field came from, so it must be local
let span = tcx.hir().span_if_local(field.did).unwrap();
- let zst = layout.map_or(false, |layout| layout.is_zst());
- let align1 = layout.map_or(false, |layout| layout.align.abi.bytes() == 1);
+ let zst = layout.is_ok_and(|layout| layout.is_zst());
+ let align1 = layout.is_ok_and(|layout| layout.align.abi.bytes() == 1);
if !zst {
return (span, zst, align1, None);
}
@@ -1468,10 +1474,10 @@ fn opaque_type_cycle_error(
let ty_span = tcx.def_span(def_id);
if !seen.contains(&ty_span) {
let descr = if ty.is_impl_trait() { "opaque " } else { "" };
- err.span_label(ty_span, &format!("returning this {descr}type `{ty}`"));
+ err.span_label(ty_span, format!("returning this {descr}type `{ty}`"));
seen.insert(ty_span);
}
- err.span_label(sp, &format!("returning here with type `{ty}`"));
+ err.span_label(sp, format!("returning here with type `{ty}`"));
}
for closure_def_id in visitor.closures {
@@ -1508,8 +1514,8 @@ fn opaque_type_cycle_error(
}
if tcx.sess.opts.unstable_opts.drop_tracking_mir
&& let DefKind::Generator = tcx.def_kind(closure_def_id)
+ && let Some(generator_layout) = tcx.mir_generator_witnesses(closure_def_id)
{
- let generator_layout = tcx.mir_generator_witnesses(closure_def_id);
for interior_ty in &generator_layout.field_tys {
label_match(interior_ty.ty, interior_ty.source_info.span);
}
diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
index 5d119a773..8bf1e0e84 100644
--- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
+++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs
@@ -60,19 +60,21 @@ pub(super) fn compare_impl_method<'tcx>(
};
}
-/// This function is best explained by example. Consider a trait:
+/// This function is best explained by example. Consider a trait with it's implementation:
///
-/// trait Trait<'t, T> {
-/// // `trait_m`
-/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
-/// }
+/// ```rust
+/// trait Trait<'t, T> {
+/// // `trait_m`
+/// fn method<'a, M>(t: &'t T, m: &'a M) -> Self;
+/// }
///
-/// And an impl:
+/// struct Foo;
///
-/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
-/// // `impl_m`
-/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo;
-/// }
+/// impl<'i, 'j, U> Trait<'j, &'i U> for Foo {
+/// // `impl_m`
+/// fn method<'b, N>(t: &'j &'i U, m: &'b N) -> Foo { Foo }
+/// }
+/// ```
///
/// We wish to decide if those two method types are compatible.
/// For this we have to show that, assuming the bounds of the impl hold, the
@@ -82,7 +84,9 @@ pub(super) fn compare_impl_method<'tcx>(
/// type parameters to impl type parameters. This is taken from the
/// impl trait reference:
///
-/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+/// ```rust,ignore (pseudo-Rust)
+/// trait_to_impl_substs = {'t => 'j, T => &'i U, Self => Foo}
+/// ```
///
/// We create a mapping `dummy_substs` that maps from the impl type
/// parameters to fresh types and regions. For type parameters,
@@ -91,13 +95,17 @@ pub(super) fn compare_impl_method<'tcx>(
/// regions (Note: but only early-bound regions, i.e., those
/// declared on the impl or used in type parameter bounds).
///
-/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+/// ```rust,ignore (pseudo-Rust)
+/// impl_to_placeholder_substs = {'i => 'i0, U => U0, N => N0 }
+/// ```
///
/// Now we can apply `placeholder_substs` to the type of the impl method
/// to yield a new function type in terms of our fresh, placeholder
/// types:
///
-/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+/// ```rust,ignore (pseudo-Rust)
+/// <'b> fn(t: &'i0 U0, m: &'b) -> Foo
+/// ```
///
/// We now want to extract and substitute the type of the *trait*
/// method and compare it. To do so, we must create a compound
@@ -106,11 +114,15 @@ pub(super) fn compare_impl_method<'tcx>(
/// type parameters. We extend the mapping to also include
/// the method parameters.
///
-/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+/// ```rust,ignore (pseudo-Rust)
+/// trait_to_placeholder_substs = { T => &'i0 U0, Self => Foo, M => N0 }
+/// ```
///
/// Applying this to the trait method type yields:
///
-/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+/// ```rust,ignore (pseudo-Rust)
+/// <'a> fn(t: &'i0 U0, m: &'a) -> Foo
+/// ```
///
/// This type is also the same but the name of the bound region (`'a`
/// vs `'b`). However, the normal subtyping rules on fn types handle
@@ -579,7 +591,7 @@ fn compare_asyncness<'tcx>(
pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
tcx: TyCtxt<'tcx>,
impl_m_def_id: LocalDefId,
-) -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed> {
+) -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed> {
let impl_m = tcx.opt_associated_item(impl_m_def_id.to_def_id()).unwrap();
let trait_m = tcx.opt_associated_item(impl_m.trait_item_def_id.unwrap()).unwrap();
let impl_trait_ref =
@@ -782,14 +794,14 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>(
})
});
debug!(%ty);
- collected_tys.insert(def_id, ty);
+ collected_tys.insert(def_id, ty::EarlyBinder(ty));
}
Err(err) => {
let reported = tcx.sess.delay_span_bug(
return_span,
format!("could not fully resolve: {ty} => {err:?}"),
);
- collected_tys.insert(def_id, tcx.ty_error(reported));
+ collected_tys.insert(def_id, ty::EarlyBinder(tcx.ty_error(reported)));
}
}
}
@@ -839,7 +851,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ImplTraitInTraitCollector<'_, 'tcx> {
});
self.types.insert(proj.def_id, (infer_ty, proj.substs));
// Recurse into bounds
- for (pred, pred_span) in self.interner().bound_explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) {
+ for (pred, pred_span) in self.interner().explicit_item_bounds(proj.def_id).subst_iter_copied(self.interner(), proj.substs) {
let pred = pred.fold_with(self);
let pred = self.ocx.normalize(
&ObligationCause::misc(self.span, self.body_id),
@@ -1163,7 +1175,7 @@ fn compare_self_type<'tcx>(
/// as the number of generics on the respective assoc item in the trait definition.
///
/// For example this code emits the errors in the following code:
-/// ```
+/// ```rust,compile_fail
/// trait Trait {
/// fn foo();
/// type Assoc<T>;
@@ -1273,7 +1285,7 @@ fn compare_number_of_generics<'tcx>(
let mut err = tcx.sess.struct_span_err_with_code(
spans,
- &format!(
+ format!(
"{} `{}` has {} {kind} parameter{} but its trait \
declaration has {} {kind} parameter{}",
item_kind,
@@ -1317,7 +1329,7 @@ fn compare_number_of_generics<'tcx>(
impl_count,
kind,
pluralize!(impl_count),
- suffix.unwrap_or_else(String::new),
+ suffix.unwrap_or_default(),
),
);
}
@@ -1547,7 +1559,7 @@ fn compare_synthetic_generics<'tcx>(
/// the same kind as the respective generic parameter in the trait def.
///
/// For example all 4 errors in the following code are emitted here:
-/// ```
+/// ```rust,ignore (pseudo-Rust)
/// trait Foo {
/// fn foo<const N: u8>();
/// type bar<const N: u8>;
@@ -2023,7 +2035,7 @@ pub(super) fn check_type_bounds<'tcx>(
};
let obligations: Vec<_> = tcx
- .bound_explicit_item_bounds(trait_ty.def_id)
+ .explicit_item_bounds(trait_ty.def_id)
.subst_iter_copied(tcx, rebased_substs)
.map(|(concrete_ty_bound, span)| {
debug!("check_type_bounds: concrete_ty_bound = {:?}", concrete_ty_bound);
diff --git a/compiler/rustc_hir_analysis/src/check/dropck.rs b/compiler/rustc_hir_analysis/src/check/dropck.rs
index 111bf5e54..e0ba255cc 100644
--- a/compiler/rustc_hir_analysis/src/check/dropck.rs
+++ b/compiler/rustc_hir_analysis/src/check/dropck.rs
@@ -1,13 +1,17 @@
// FIXME(@lcnr): Move this module out of `rustc_hir_analysis`.
//
// We don't do any drop checking during hir typeck.
-use crate::hir::def_id::{DefId, LocalDefId};
+use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{struct_span_err, ErrorGuaranteed};
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_infer::infer::outlives::env::OutlivesEnvironment;
+use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::util::IgnoreRegions;
-use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
+use rustc_middle::ty::util::CheckRegions;
+use rustc_middle::ty::{self, TyCtxt};
+use rustc_trait_selection::traits::{self, ObligationCtxt};
+
+use crate::errors;
+use crate::hir::def_id::{DefId, LocalDefId};
/// This function confirms that the `Drop` implementation identified by
/// `drop_impl_did` is not any more specialized than the type it is
@@ -27,22 +31,34 @@ use rustc_middle::ty::{self, Predicate, Ty, TyCtxt};
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
///
pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorGuaranteed> {
+ match tcx.impl_polarity(drop_impl_did) {
+ ty::ImplPolarity::Positive => {}
+ ty::ImplPolarity::Negative => {
+ return Err(tcx.sess.emit_err(errors::DropImplPolarity::Negative {
+ span: tcx.def_span(drop_impl_did),
+ }));
+ }
+ ty::ImplPolarity::Reservation => {
+ return Err(tcx.sess.emit_err(errors::DropImplPolarity::Reservation {
+ span: tcx.def_span(drop_impl_did),
+ }));
+ }
+ }
let dtor_self_type = tcx.type_of(drop_impl_did).subst_identity();
- let dtor_predicates = tcx.predicates_of(drop_impl_did);
match dtor_self_type.kind() {
- ty::Adt(adt_def, self_to_impl_substs) => {
+ ty::Adt(adt_def, adt_to_impl_substs) => {
ensure_drop_params_and_item_params_correspond(
tcx,
drop_impl_did.expect_local(),
adt_def.did(),
- self_to_impl_substs,
+ adt_to_impl_substs,
)?;
ensure_drop_predicates_are_implied_by_item_defn(
tcx,
- dtor_predicates,
+ drop_impl_did.expect_local(),
adt_def.did().expect_local(),
- self_to_impl_substs,
+ adt_to_impl_substs,
)
}
_ => {
@@ -52,7 +68,7 @@ pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), Erro
let span = tcx.def_span(drop_impl_did);
let reported = tcx.sess.delay_span_bug(
span,
- &format!("should have been rejected by coherence check: {dtor_self_type}"),
+ format!("should have been rejected by coherence check: {dtor_self_type}"),
);
Err(reported)
}
@@ -63,9 +79,9 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
tcx: TyCtxt<'tcx>,
drop_impl_did: LocalDefId,
self_type_did: DefId,
- drop_impl_substs: SubstsRef<'tcx>,
+ adt_to_impl_substs: SubstsRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
- let Err(arg) = tcx.uses_unique_generic_params(drop_impl_substs, IgnoreRegions::No) else {
+ let Err(arg) = tcx.uses_unique_generic_params(adt_to_impl_substs, CheckRegions::OnlyEarlyBound) else {
return Ok(())
};
@@ -76,15 +92,15 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
struct_span_err!(tcx.sess, drop_impl_span, E0366, "`Drop` impls cannot be specialized");
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- err.note(&format!("`{arg}` is mentioned multiple times"))
+ err.note(format!("`{arg}` is mentioned multiple times"))
}
ty::util::NotUniqueParam::NotParam(arg) => {
- err.note(&format!("`{arg}` is not a generic parameter"))
+ err.note(format!("`{arg}` is not a generic parameter"))
}
};
err.span_note(
item_span,
- &format!(
+ format!(
"use the same sequence of generic lifetime, type and const parameters \
as the {self_descr} definition",
),
@@ -96,237 +112,94 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
/// implied by assuming the predicates attached to self_type_did.
fn ensure_drop_predicates_are_implied_by_item_defn<'tcx>(
tcx: TyCtxt<'tcx>,
- dtor_predicates: ty::GenericPredicates<'tcx>,
- self_type_did: LocalDefId,
- self_to_impl_substs: SubstsRef<'tcx>,
+ drop_impl_def_id: LocalDefId,
+ adt_def_id: LocalDefId,
+ adt_to_impl_substs: SubstsRef<'tcx>,
) -> Result<(), ErrorGuaranteed> {
- let mut result = Ok(());
-
- // Here is an example, analogous to that from
- // `compare_impl_method`.
- //
- // Consider a struct type:
- //
- // struct Type<'c, 'b:'c, 'a> {
- // x: &'a Contents // (contents are irrelevant;
- // y: &'c Cell<&'b Contents>, // only the bounds matter for our purposes.)
- // }
- //
- // and a Drop impl:
- //
- // impl<'z, 'y:'z, 'x:'y> Drop for P<'z, 'y, 'x> {
- // fn drop(&mut self) { self.y.set(self.x); } // (only legal if 'x: 'y)
- // }
- //
- // We start out with self_to_impl_substs, that maps the generic
- // parameters of Type to that of the Drop impl.
- //
- // self_to_impl_substs = {'c => 'z, 'b => 'y, 'a => 'x}
- //
- // Applying this to the predicates (i.e., assumptions) provided by the item
- // definition yields the instantiated assumptions:
- //
- // ['y : 'z]
+ let infcx = tcx.infer_ctxt().build();
+ let ocx = ObligationCtxt::new(&infcx);
+
+ // Take the param-env of the adt and substitute the substs that show up in
+ // the implementation's self type. This gives us the assumptions that the
+ // self ty of the implementation is allowed to know just from it being a
+ // well-formed adt, since that's all we're allowed to assume while proving
+ // the Drop implementation is not specialized.
//
- // We then check all of the predicates of the Drop impl:
- //
- // ['y:'z, 'x:'y]
- //
- // and ensure each is in the list of instantiated
- // assumptions. Here, `'y:'z` is present, but `'x:'y` is
- // absent. So we report an error that the Drop impl injected a
- // predicate that is not present on the struct definition.
-
- // We can assume the predicates attached to struct/enum definition
- // hold.
- let generic_assumptions = tcx.predicates_of(self_type_did);
-
- let assumptions_in_impl_context = generic_assumptions.instantiate(tcx, &self_to_impl_substs);
- let assumptions_in_impl_context = assumptions_in_impl_context.predicates;
-
- debug!(?assumptions_in_impl_context, ?dtor_predicates.predicates);
-
- let self_param_env = tcx.param_env(self_type_did);
-
- // An earlier version of this code attempted to do this checking
- // via the traits::fulfill machinery. However, it ran into trouble
- // since the fulfill machinery merely turns outlives-predicates
- // 'a:'b and T:'b into region inference constraints. It is simpler
- // just to look for all the predicates directly.
-
- assert_eq!(dtor_predicates.parent, None);
- for &(predicate, predicate_sp) in dtor_predicates.predicates {
- // (We do not need to worry about deep analysis of type
- // expressions etc because the Drop impls are already forced
- // to take on a structure that is roughly an alpha-renaming of
- // the generic parameters of the item definition.)
-
- // This path now just checks *all* predicates via an instantiation of
- // the `SimpleEqRelation`, which simply forwards to the `relate` machinery
- // after taking care of anonymizing late bound regions.
- //
- // However, it may be more efficient in the future to batch
- // the analysis together via the fulfill (see comment above regarding
- // the usage of the fulfill machinery), rather than the
- // repeated `.iter().any(..)` calls.
+ // We don't need to normalize this param-env or anything, since we're only
+ // substituting it with free params, so no additional param-env normalization
+ // can occur on top of what has been done in the param_env query itself.
+ let param_env = ty::EarlyBinder(tcx.param_env(adt_def_id))
+ .subst(tcx, adt_to_impl_substs)
+ .with_constness(tcx.constness(drop_impl_def_id));
+
+ for (pred, span) in tcx.predicates_of(drop_impl_def_id).instantiate_identity(tcx) {
+ let normalize_cause = traits::ObligationCause::misc(span, adt_def_id);
+ let pred = ocx.normalize(&normalize_cause, param_env, pred);
+ let cause = traits::ObligationCause::new(span, adt_def_id, traits::DropImpl);
+ ocx.register_obligation(traits::Obligation::new(tcx, cause, param_env, pred));
+ }
- // This closure is a more robust way to check `Predicate` equality
- // than simple `==` checks (which were the previous implementation).
- // It relies on `ty::relate` for `TraitPredicate`, `ProjectionPredicate`,
- // `ConstEvaluatable` and `TypeOutlives` (which implement the Relate trait),
- // while delegating on simple equality for the other `Predicate`.
- // This implementation solves (Issue #59497) and (Issue #58311).
- // It is unclear to me at the moment whether the approach based on `relate`
- // could be extended easily also to the other `Predicate`.
- let predicate_matches_closure = |p: Predicate<'tcx>| {
- let mut relator: SimpleEqRelation<'tcx> = SimpleEqRelation::new(tcx, self_param_env);
- let predicate = predicate.kind();
- let p = p.kind();
- match (predicate.skip_binder(), p.skip_binder()) {
- (
- ty::PredicateKind::Clause(ty::Clause::Trait(a)),
- ty::PredicateKind::Clause(ty::Clause::Trait(b)),
- ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
- (
- ty::PredicateKind::Clause(ty::Clause::Projection(a)),
- ty::PredicateKind::Clause(ty::Clause::Projection(b)),
- ) => relator.relate(predicate.rebind(a), p.rebind(b)).is_ok(),
- (
- ty::PredicateKind::ConstEvaluatable(a),
- ty::PredicateKind::ConstEvaluatable(b),
- ) => relator.relate(predicate.rebind(a), predicate.rebind(b)).is_ok(),
- (
- ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
- ty_a,
- lt_a,
- ))),
- ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
- ty_b,
- lt_b,
- ))),
- ) => {
- relator.relate(predicate.rebind(ty_a), p.rebind(ty_b)).is_ok()
- && relator.relate(predicate.rebind(lt_a), p.rebind(lt_b)).is_ok()
- }
- (ty::PredicateKind::WellFormed(arg_a), ty::PredicateKind::WellFormed(arg_b)) => {
- relator.relate(predicate.rebind(arg_a), p.rebind(arg_b)).is_ok()
- }
- _ => predicate == p,
+ // All of the custom error reporting logic is to preserve parity with the old
+ // error messages.
+ //
+ // They can probably get removed with better treatment of the new `DropImpl`
+ // obligation cause code, and perhaps some custom logic in `report_region_errors`.
+
+ let errors = ocx.select_all_or_error();
+ if !errors.is_empty() {
+ let mut guar = None;
+ let mut root_predicates = FxHashSet::default();
+ for error in errors {
+ let root_predicate = error.root_obligation.predicate;
+ if root_predicates.insert(root_predicate) {
+ let item_span = tcx.def_span(adt_def_id);
+ let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+ guar = Some(
+ struct_span_err!(
+ tcx.sess,
+ error.root_obligation.cause.span,
+ E0367,
+ "`Drop` impl requires `{root_predicate}` \
+ but the {self_descr} it is implemented for does not",
+ )
+ .span_note(item_span, "the implementor must specify the same requirement")
+ .emit(),
+ );
}
- };
-
- if !assumptions_in_impl_context.iter().copied().any(predicate_matches_closure) {
- let item_span = tcx.def_span(self_type_did);
- let self_descr = tcx.def_descr(self_type_did.to_def_id());
- let reported = struct_span_err!(
- tcx.sess,
- predicate_sp,
- E0367,
- "`Drop` impl requires `{predicate}` but the {self_descr} it is implemented for does not",
- )
- .span_note(item_span, "the implementor must specify the same requirement")
- .emit();
- result = Err(reported);
}
+ return Err(guar.unwrap());
}
- result
-}
-
-/// This is an implementation of the [`TypeRelation`] trait with the
-/// aim of simply comparing for equality (without side-effects).
-///
-/// It is not intended to be used anywhere else other than here.
-pub(crate) struct SimpleEqRelation<'tcx> {
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
-}
-
-impl<'tcx> SimpleEqRelation<'tcx> {
- fn new(tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> SimpleEqRelation<'tcx> {
- SimpleEqRelation { tcx, param_env }
- }
-}
-
-impl<'tcx> TypeRelation<'tcx> for SimpleEqRelation<'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
- }
-
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
-
- fn tag(&self) -> &'static str {
- "dropck::SimpleEqRelation"
- }
-
- fn a_is_expected(&self) -> bool {
- true
- }
-
- fn relate_with_variance<T: Relate<'tcx>>(
- &mut self,
- _: ty::Variance,
- _info: ty::VarianceDiagInfo<'tcx>,
- a: T,
- b: T,
- ) -> RelateResult<'tcx, T> {
- // Here we ignore variance because we require drop impl's types
- // to be *exactly* the same as to the ones in the struct definition.
- self.relate(a, b)
- }
-
- fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- debug!("SimpleEqRelation::tys(a={:?}, b={:?})", a, b);
- ty::relate::super_relate_tys(self, a, b)
- }
-
- fn regions(
- &mut self,
- a: ty::Region<'tcx>,
- b: ty::Region<'tcx>,
- ) -> RelateResult<'tcx, ty::Region<'tcx>> {
- debug!("SimpleEqRelation::regions(a={:?}, b={:?})", a, b);
-
- // We can just equate the regions because LBRs have been
- // already anonymized.
- if a == b {
- Ok(a)
- } else {
- // I'm not sure is this `TypeError` is the right one, but
- // it should not matter as it won't be checked (the dropck
- // will emit its own, more informative and higher-level errors
- // in case anything goes wrong).
- Err(TypeError::RegionsPlaceholderMismatch)
+ let errors = ocx.infcx.resolve_regions(&OutlivesEnvironment::new(param_env));
+ if !errors.is_empty() {
+ let mut guar = None;
+ for error in errors {
+ let item_span = tcx.def_span(adt_def_id);
+ let self_descr = tcx.def_descr(adt_def_id.to_def_id());
+ let outlives = match error {
+ RegionResolutionError::ConcreteFailure(_, a, b) => format!("{b}: {a}"),
+ RegionResolutionError::GenericBoundFailure(_, generic, r) => {
+ format!("{generic}: {r}")
+ }
+ RegionResolutionError::SubSupConflict(_, _, _, a, _, b, _) => format!("{b}: {a}"),
+ RegionResolutionError::UpperBoundUniverseConflict(a, _, _, _, b) => {
+ format!("{b}: {a}", a = tcx.mk_re_var(a))
+ }
+ };
+ guar = Some(
+ struct_span_err!(
+ tcx.sess,
+ error.origin().span(),
+ E0367,
+ "`Drop` impl requires `{outlives}` \
+ but the {self_descr} it is implemented for does not",
+ )
+ .span_note(item_span, "the implementor must specify the same requirement")
+ .emit(),
+ );
}
+ return Err(guar.unwrap());
}
- fn consts(
- &mut self,
- a: ty::Const<'tcx>,
- b: ty::Const<'tcx>,
- ) -> RelateResult<'tcx, ty::Const<'tcx>> {
- debug!("SimpleEqRelation::consts(a={:?}, b={:?})", a, b);
- ty::relate::super_relate_consts(self, a, b)
- }
-
- fn binders<T>(
- &mut self,
- a: ty::Binder<'tcx, T>,
- b: ty::Binder<'tcx, T>,
- ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
- where
- T: Relate<'tcx>,
- {
- debug!("SimpleEqRelation::binders({:?}: {:?}", a, b);
-
- // Anonymizing the LBRs is necessary to solve (Issue #59497).
- // After we do so, it should be totally fine to skip the binders.
- let anon_a = self.tcx.anonymize_bound_vars(a);
- let anon_b = self.tcx.anonymize_bound_vars(b);
- self.relate(anon_a.skip_binder(), anon_b.skip_binder())?;
-
- Ok(a)
- }
+ Ok(())
}
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsic.rs b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
index 854974d16..e8785235c 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsic.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsic.rs
@@ -198,7 +198,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
| sym::assert_zero_valid
| sym::assert_mem_uninitialized_valid => (1, Vec::new(), tcx.mk_unit()),
sym::forget => (1, vec![param(0)], tcx.mk_unit()),
- sym::transmute => (2, vec![param(0)], param(1)),
+ sym::transmute | sym::transmute_unchecked => (2, vec![param(0)], param(1)),
sym::prefetch_read_data
| sym::prefetch_write_data
| sym::prefetch_read_instruction
@@ -215,7 +215,8 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::type_name => (1, Vec::new(), tcx.mk_static_str()),
sym::type_id => (1, Vec::new(), tcx.types.u64),
- sym::offset | sym::arith_offset => (
+ sym::offset => (2, vec![param(0), param(1)], param(0)),
+ sym::arith_offset => (
1,
vec![
tcx.mk_ptr(ty::TypeAndMut { ty: param(0), mutbl: hir::Mutability::Not }),
@@ -380,6 +381,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) {
sym::unlikely => (0, vec![tcx.types.bool], tcx.types.bool),
sym::read_via_copy => (1, vec![tcx.mk_imm_ptr(param(0))], param(0)),
+ sym::write_via_move => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()),
sym::discriminant_value => {
let assoc_items = tcx.associated_item_def_ids(
@@ -545,14 +547,14 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>)
Err(_) => {
let msg =
format!("unrecognized platform-specific intrinsic function: `{name}`");
- tcx.sess.struct_span_err(it.span, &msg).emit();
+ tcx.sess.struct_span_err(it.span, msg).emit();
return;
}
}
}
_ => {
let msg = format!("unrecognized platform-specific intrinsic function: `{name}`");
- tcx.sess.struct_span_err(it.span, &msg).emit();
+ tcx.sess.struct_span_err(it.span, msg).emit();
return;
}
};
diff --git a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
index 0d482b53a..0bb1467ef 100644
--- a/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
+++ b/compiler/rustc_hir_analysis/src/check/intrinsicck.rs
@@ -84,33 +84,45 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
ty::Adt(adt, substs) if adt.repr().simd() => {
let fields = &adt.non_enum_variant().fields;
let elem_ty = fields[FieldIdx::from_u32(0)].ty(self.tcx, substs);
- match elem_ty.kind() {
- ty::Never | ty::Error(_) => return None,
- ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => {
- Some(InlineAsmType::VecI8(fields.len() as u64))
+
+ let (size, ty) = match elem_ty.kind() {
+ ty::Array(ty, len) => {
+ if let Some(len) =
+ len.try_eval_target_usize(self.tcx, self.tcx.param_env(adt.did()))
+ {
+ (len, *ty)
+ } else {
+ return None;
+ }
}
+ _ => (fields.len() as u64, elem_ty),
+ };
+
+ match ty.kind() {
+ ty::Never | ty::Error(_) => return None,
+ ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::VecI8(size)),
ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => {
- Some(InlineAsmType::VecI16(fields.len() as u64))
+ Some(InlineAsmType::VecI16(size))
}
ty::Int(IntTy::I32) | ty::Uint(UintTy::U32) => {
- Some(InlineAsmType::VecI32(fields.len() as u64))
+ Some(InlineAsmType::VecI32(size))
}
ty::Int(IntTy::I64) | ty::Uint(UintTy::U64) => {
- Some(InlineAsmType::VecI64(fields.len() as u64))
+ Some(InlineAsmType::VecI64(size))
}
ty::Int(IntTy::I128) | ty::Uint(UintTy::U128) => {
- Some(InlineAsmType::VecI128(fields.len() as u64))
+ Some(InlineAsmType::VecI128(size))
}
ty::Int(IntTy::Isize) | ty::Uint(UintTy::Usize) => {
Some(match self.tcx.sess.target.pointer_width {
- 16 => InlineAsmType::VecI16(fields.len() as u64),
- 32 => InlineAsmType::VecI32(fields.len() as u64),
- 64 => InlineAsmType::VecI64(fields.len() as u64),
+ 16 => InlineAsmType::VecI16(size),
+ 32 => InlineAsmType::VecI32(size),
+ 64 => InlineAsmType::VecI64(size),
_ => unreachable!(),
})
}
- ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(fields.len() as u64)),
- ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(fields.len() as u64)),
+ ty::Float(FloatTy::F32) => Some(InlineAsmType::VecF32(size)),
+ ty::Float(FloatTy::F64) => Some(InlineAsmType::VecF64(size)),
_ => None,
}
}
@@ -118,7 +130,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
_ => None,
};
let Some(asm_ty) = asm_ty else {
- let msg = &format!("cannot use value of type `{ty}` for inline assembly");
+ let msg = format!("cannot use value of type `{ty}` for inline assembly");
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
err.note(
"only integers, floats, SIMD vectors, pointers and function pointers \
@@ -133,7 +145,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
if !ty.is_copy_modulo_regions(self.tcx, self.param_env) {
let msg = "arguments for inline assembly must be copyable";
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
- err.note(&format!("`{ty}` does not implement the Copy trait"));
+ err.note(format!("`{ty}` does not implement the Copy trait"));
err.emit();
}
@@ -152,8 +164,8 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let mut err = self.tcx.sess.struct_span_err(vec![in_expr.span, expr.span], msg);
let in_expr_ty = (self.get_operand_ty)(in_expr);
- err.span_label(in_expr.span, &format!("type `{in_expr_ty}`"));
- err.span_label(expr.span, &format!("type `{ty}`"));
+ err.span_label(in_expr.span, format!("type `{in_expr_ty}`"));
+ err.span_label(expr.span, format!("type `{ty}`"));
err.note(
"asm inout arguments must have the same type, \
unless they are both pointers or integers of the same size",
@@ -172,17 +184,17 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
let reg_class = reg.reg_class();
let supported_tys = reg_class.supported_types(asm_arch);
let Some((_, feature)) = supported_tys.iter().find(|&&(t, _)| t == asm_ty) else {
- let msg = &format!("type `{ty}` cannot be used with this register class");
+ let msg = format!("type `{ty}` cannot be used with this register class");
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
let supported_tys: Vec<_> =
supported_tys.iter().map(|(t, _)| t.to_string()).collect();
- err.note(&format!(
+ err.note(format!(
"register class `{}` supports these types: {}",
reg_class.name(),
supported_tys.join(", "),
));
if let Some(suggest) = reg_class.suggest_class(asm_arch, asm_ty) {
- err.help(&format!(
+ err.help(format!(
"consider using the `{}` register class instead",
suggest.name()
));
@@ -203,9 +215,9 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
// register class is usable at all.
if let Some(feature) = feature {
if !target_features.contains(feature) {
- let msg = &format!("`{}` target feature is not enabled", feature);
+ let msg = format!("`{}` target feature is not enabled", feature);
let mut err = self.tcx.sess.struct_span_err(expr.span, msg);
- err.note(&format!(
+ err.note(format!(
"this is required to use type `{}` with register class `{}`",
ty,
reg_class.name(),
@@ -240,10 +252,10 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
"formatting may not be suitable for sub-register argument",
|lint| {
lint.span_label(expr.span, "for this argument");
- lint.help(&format!(
+ lint.help(format!(
"use `{{{idx}:{suggested_modifier}}}` to have the register formatted as `{suggested_result}`",
));
- lint.help(&format!(
+ lint.help(format!(
"or use `{{{idx}:{default_modifier}}}` to keep the default formatting of `{default_result}`",
));
lint
@@ -289,7 +301,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
op.is_clobber(),
) {
let msg = format!("cannot use register `{}`: {}", reg.name(), msg);
- self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
+ self.tcx.sess.struct_span_err(*op_sp, msg).emit();
continue;
}
}
@@ -328,7 +340,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
reg_class.name(),
feature
);
- self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
+ self.tcx.sess.struct_span_err(*op_sp, msg).emit();
// register isn't enabled, don't do more checks
continue;
}
@@ -342,7 +354,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
.intersperse(", ")
.collect::<String>(),
);
- self.tcx.sess.struct_span_err(*op_sp, &msg).emit();
+ self.tcx.sess.struct_span_err(*op_sp, msg).emit();
// register isn't enabled, don't do more checks
continue;
}
@@ -424,7 +436,7 @@ impl<'a, 'tcx> InlineAsmCtxt<'a, 'tcx> {
self.tcx.sess.struct_span_err(*op_sp, "invalid `sym` operand");
err.span_label(
self.tcx.def_span(anon_const.def_id),
- &format!("is {} `{}`", ty.kind().article(), ty),
+ format!("is {} `{}`", ty.kind().article(), ty),
);
err.help("`sym` operands must refer to either a function or a static");
err.emit();
diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs
index 8fe4c44fc..3971a4c01 100644
--- a/compiler/rustc_hir_analysis/src/check/mod.rs
+++ b/compiler/rustc_hir_analysis/src/check/mod.rs
@@ -74,11 +74,11 @@ pub use check::check_abi;
use check::check_mod_item_types;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_errors::{pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder};
+use rustc_errors::{pluralize, struct_span_err, Diagnostic, DiagnosticBuilder};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::intravisit::Visitor;
use rustc_index::bit_set::BitSet;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::ty::{InternalSubsts, SubstsRef};
use rustc_session::parse::feature_err;
@@ -90,6 +90,7 @@ use rustc_target::spec::abi::Abi;
use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor;
use std::num::NonZeroU32;
+use crate::errors;
use crate::require_c_abi_if_c_variadic;
use crate::util::common::indenter;
@@ -171,34 +172,18 @@ fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId) {
fn report_forbidden_specialization(tcx: TyCtxt<'_>, impl_item: DefId, parent_impl: DefId) {
let span = tcx.def_span(impl_item);
let ident = tcx.item_name(impl_item);
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0520,
- "`{}` specializes an item from a parent `impl`, but that item is not marked `default`",
- ident,
- );
- err.span_label(span, format!("cannot specialize default item `{}`", ident));
-
- match tcx.span_of_impl(parent_impl) {
- Ok(span) => {
- err.span_label(span, "parent `impl` is here");
- err.note(&format!(
- "to specialize, `{}` in the parent `impl` must be marked `default`",
- ident
- ));
- }
- Err(cname) => {
- err.note(&format!("parent implementation is in crate `{cname}`"));
- }
- }
- err.emit();
+ let err = match tcx.span_of_impl(parent_impl) {
+ Ok(sp) => errors::ImplNotMarkedDefault::Ok { span, ident, ok_label: sp },
+ Err(cname) => errors::ImplNotMarkedDefault::Err { span, ident, cname },
+ };
+
+ tcx.sess.emit_err(err);
}
fn missing_items_err(
tcx: TyCtxt<'_>,
- impl_span: Span,
+ impl_def_id: LocalDefId,
missing_items: &[ty::AssocItem],
full_impl_span: Span,
) {
@@ -211,14 +196,6 @@ fn missing_items_err(
.collect::<Vec<_>>()
.join("`, `");
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0046,
- "not all trait items implemented, missing: `{missing_items_msg}`",
- );
- err.span_label(impl_span, format!("missing `{missing_items_msg}` in implementation"));
-
// `Span` before impl block closing brace.
let hi = full_impl_span.hi() - BytePos(1);
// Point at the place right before the closing brace of the relevant `impl` to suggest
@@ -227,20 +204,40 @@ fn missing_items_err(
// Obtain the level of indentation ending in `sugg_sp`.
let padding =
tcx.sess.source_map().indentation_before(sugg_sp).unwrap_or_else(|| String::new());
+ let (mut missing_trait_item, mut missing_trait_item_none, mut missing_trait_item_label) =
+ (Vec::new(), Vec::new(), Vec::new());
for &trait_item in missing_items {
- let snippet = suggestion_signature(trait_item, tcx);
+ let snippet = suggestion_signature(
+ tcx,
+ trait_item,
+ tcx.impl_trait_ref(impl_def_id).unwrap().subst_identity(),
+ );
let code = format!("{}{}\n{}", padding, snippet, padding);
- let msg = format!("implement the missing item: `{snippet}`");
- let appl = Applicability::HasPlaceholders;
if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) {
- err.span_label(span, format!("`{}` from trait", trait_item.name));
- err.tool_only_span_suggestion(sugg_sp, &msg, code, appl);
+ missing_trait_item_label
+ .push(errors::MissingTraitItemLabel { span, item: trait_item.name });
+ missing_trait_item.push(errors::MissingTraitItemSuggestion {
+ span: sugg_sp,
+ code,
+ snippet,
+ });
} else {
- err.span_suggestion_hidden(sugg_sp, &msg, code, appl);
+ missing_trait_item_none.push(errors::MissingTraitItemSuggestionNone {
+ span: sugg_sp,
+ code,
+ snippet,
+ })
}
}
- err.emit();
+
+ tcx.sess.emit_err(errors::MissingTraitItem {
+ span: tcx.span_of_impl(impl_def_id.to_def_id()).unwrap(),
+ missing_items_msg,
+ missing_trait_item_label,
+ missing_trait_item,
+ missing_trait_item_none,
+ });
}
fn missing_items_must_implement_one_of_err(
@@ -252,19 +249,11 @@ fn missing_items_must_implement_one_of_err(
let missing_items_msg =
missing_items.iter().map(Ident::to_string).collect::<Vec<_>>().join("`, `");
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0046,
- "not all trait items implemented, missing one of: `{missing_items_msg}`",
- );
- err.span_label(impl_span, format!("missing one of `{missing_items_msg}` in implementation"));
-
- if let Some(annotation_span) = annotation_span {
- err.span_note(annotation_span, "required because of this annotation");
- }
-
- err.emit();
+ tcx.sess.emit_err(errors::MissingOneOfTraitItem {
+ span: impl_span,
+ note: annotation_span,
+ missing_items_msg,
+ });
}
fn default_body_is_unstable(
@@ -276,36 +265,42 @@ fn default_body_is_unstable(
issue: Option<NonZeroU32>,
) {
let missing_item_name = tcx.associated_item(item_did).name;
- let use_of_unstable_library_feature_note = match reason {
- Some(r) => format!("use of unstable library feature '{feature}': {r}"),
- None => format!("use of unstable library feature '{feature}'"),
+ let (mut some_note, mut none_note, mut reason_str) = (false, false, String::new());
+ match reason {
+ Some(r) => {
+ some_note = true;
+ reason_str = r.to_string();
+ }
+ None => none_note = true,
};
- let mut err = struct_span_err!(
- tcx.sess,
- impl_span,
- E0046,
- "not all trait items implemented, missing: `{missing_item_name}`",
- );
- err.note(format!("default implementation of `{missing_item_name}` is unstable"));
- err.note(use_of_unstable_library_feature_note);
+ let mut err = tcx.sess.create_err(errors::MissingTraitItemUnstable {
+ span: impl_span,
+ some_note,
+ none_note,
+ missing_item_name,
+ feature,
+ reason: reason_str,
+ });
+
rustc_session::parse::add_feature_diagnostics_for_issue(
&mut err,
&tcx.sess.parse_sess,
feature,
rustc_feature::GateIssue::Library(issue),
);
+
err.emit();
}
/// Re-sugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions.
fn bounds_from_generic_predicates<'tcx>(
tcx: TyCtxt<'tcx>,
- predicates: ty::GenericPredicates<'tcx>,
+ predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
) -> (String, String) {
let mut types: FxHashMap<Ty<'tcx>, Vec<DefId>> = FxHashMap::default();
let mut projections = vec![];
- for (predicate, _) in predicates.predicates {
+ for (predicate, _) in predicates {
debug!("predicate {:?}", predicate);
let bound_predicate = predicate.kind();
match bound_predicate.skip_binder() {
@@ -367,7 +362,7 @@ fn fn_sig_suggestion<'tcx>(
tcx: TyCtxt<'tcx>,
sig: ty::FnSig<'tcx>,
ident: Ident,
- predicates: ty::GenericPredicates<'tcx>,
+ predicates: impl IntoIterator<Item = (ty::Predicate<'tcx>, Span)>,
assoc: ty::AssocItem,
) -> String {
let args = sig
@@ -436,7 +431,17 @@ pub fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> {
/// Return placeholder code for the given associated item.
/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a
/// structured suggestion.
-fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String {
+fn suggestion_signature<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ assoc: ty::AssocItem,
+ impl_trait_ref: ty::TraitRef<'tcx>,
+) -> String {
+ let substs = ty::InternalSubsts::identity_for_item(tcx, assoc.def_id).rebase_onto(
+ tcx,
+ assoc.container_id(tcx),
+ impl_trait_ref.with_self_ty(tcx, tcx.types.self_param).substs,
+ );
+
match assoc.kind {
ty::AssocKind::Fn => {
// We skip the binder here because the binder would deanonymize all
@@ -445,16 +450,22 @@ fn suggestion_signature(assoc: ty::AssocItem, tcx: TyCtxt<'_>) -> String {
// regions just fine, showing `fn(&MyType)`.
fn_sig_suggestion(
tcx,
- tcx.fn_sig(assoc.def_id).subst_identity().skip_binder(),
+ tcx.fn_sig(assoc.def_id).subst(tcx, substs).skip_binder(),
assoc.ident(tcx),
- tcx.predicates_of(assoc.def_id),
+ tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
assoc,
)
}
- ty::AssocKind::Type => format!("type {} = Type;", assoc.name),
+ ty::AssocKind::Type => {
+ let (generics, where_clauses) = bounds_from_generic_predicates(
+ tcx,
+ tcx.predicates_of(assoc.def_id).instantiate_own(tcx, substs),
+ );
+ format!("type {}{generics} = /* Type */{where_clauses};", assoc.name)
+ }
ty::AssocKind::Const => {
let ty = tcx.type_of(assoc.def_id).subst_identity();
- let val = ty_kind_suggestion(ty).unwrap_or("value");
+ let val = ty_kind_suggestion(ty).unwrap_or("todo!()");
format!("const {}: {} = {};", assoc.name, ty, val)
}
}
@@ -467,16 +478,18 @@ fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>, sp: Span, d
.iter()
.map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap())
.collect();
- let msg = format!("needs exactly one variant, but has {}", adt.variants().len(),);
- let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {msg}");
- err.span_label(sp, &msg);
+ let (mut spans, mut many) = (Vec::new(), None);
if let [start @ .., end] = &*variant_spans {
- for variant_span in start {
- err.span_label(*variant_span, "");
- }
- err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did)));
+ spans = start.to_vec();
+ many = Some(*end);
}
- err.emit();
+ tcx.sess.emit_err(errors::TransparentEnumVariant {
+ span: sp,
+ spans,
+ many,
+ number: adt.variants().len(),
+ path: tcx.def_path_str(did),
+ });
}
/// Emit an error when encountering two or more non-zero-sized fields in a transparent
@@ -488,21 +501,21 @@ fn bad_non_zero_sized_fields<'tcx>(
field_spans: impl Iterator<Item = Span>,
sp: Span,
) {
- let msg = format!("needs at most one non-zero-sized field, but has {field_count}");
- let mut err = struct_span_err!(
- tcx.sess,
- sp,
- E0690,
- "{}transparent {} {}",
- if adt.is_enum() { "the variant of a " } else { "" },
- adt.descr(),
- msg,
- );
- err.span_label(sp, &msg);
- for sp in field_spans {
- err.span_label(sp, "this field is non-zero-sized");
+ if adt.is_enum() {
+ tcx.sess.emit_err(errors::TransparentNonZeroSizedEnum {
+ span: sp,
+ spans: field_spans.collect(),
+ field_count,
+ desc: adt.descr(),
+ });
+ } else {
+ tcx.sess.emit_err(errors::TransparentNonZeroSized {
+ span: sp,
+ spans: field_spans.collect(),
+ field_count,
+ desc: adt.descr(),
+ });
}
- err.emit();
}
// FIXME: Consider moving this method to a more fitting place.
diff --git a/compiler/rustc_hir_analysis/src/check/region.rs b/compiler/rustc_hir_analysis/src/check/region.rs
index b28bfb1d5..6ab5556e9 100644
--- a/compiler/rustc_hir_analysis/src/check/region.rs
+++ b/compiler/rustc_hir_analysis/src/check/region.rs
@@ -12,7 +12,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Arm, Block, Expr, Local, Pat, PatKind, Stmt};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::middle::region::*;
use rustc_middle::ty::TyCtxt;
use rustc_span::source_map;
@@ -421,7 +421,7 @@ fn resolve_expr<'tcx>(visitor: &mut RegionResolutionVisitor<'tcx>, expr: &'tcx h
let target_scopes = visitor.fixup_scopes.drain(start_point..);
for scope in target_scopes {
- let mut yield_data =
+ let yield_data =
visitor.scope_tree.yield_in_scope.get_mut(&scope).unwrap().last_mut().unwrap();
let count = yield_data.expr_and_pat_count;
let span = yield_data.span;
diff --git a/compiler/rustc_hir_analysis/src/check/wfcheck.rs b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
index 53197bc84..b403ee96b 100644
--- a/compiler/rustc_hir_analysis/src/check/wfcheck.rs
+++ b/compiler/rustc_hir_analysis/src/check/wfcheck.rs
@@ -12,7 +12,7 @@ use rustc_infer::infer::outlives::env::{OutlivesEnvironment, RegionBoundPairs};
use rustc_infer::infer::outlives::obligations::TypeOutlives;
use rustc_infer::infer::{self, InferCtxt, TyCtxtInferExt};
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::trait_def::TraitSpecializationKind;
use rustc_middle::ty::{
self, AdtKind, GenericParamDefKind, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
@@ -155,7 +155,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
debug!(
?item.owner_id,
- item.name = ? tcx.def_path_str(def_id.to_def_id())
+ item.name = ? tcx.def_path_str(def_id)
);
match item.kind {
@@ -179,7 +179,7 @@ fn check_item<'tcx>(tcx: TyCtxt<'tcx>, item: &'tcx hir::Item<'tcx>) {
hir::ItemKind::Impl(impl_) => {
let is_auto = tcx
.impl_trait_ref(def_id)
- .map_or(false, |trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
+ .is_some_and(|trait_ref| tcx.trait_is_auto(trait_ref.skip_binder().def_id));
if let (hir::Defaultness::Default { .. }, true) = (impl_.defaultness, is_auto) {
let sp = impl_.of_trait.as_ref().map_or(item.span, |t| t.path.span);
let mut err =
@@ -251,7 +251,7 @@ fn check_foreign_item(tcx: TyCtxt<'_>, item: &hir::ForeignItem<'_>) {
debug!(
?item.owner_id,
- item.name = ? tcx.def_path_str(def_id.to_def_id())
+ item.name = ? tcx.def_path_str(def_id)
);
match item.kind {
@@ -360,7 +360,9 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
tcx,
param_env,
item_def_id,
- tcx.explicit_item_bounds(item_def_id).to_vec(),
+ tcx.explicit_item_bounds(item_def_id)
+ .subst_identity_iter_copied()
+ .collect::<Vec<_>>(),
&FxIndexSet::default(),
gat_def_id.def_id,
gat_generics,
@@ -443,7 +445,7 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
let plural = pluralize!(unsatisfied_bounds.len());
let mut err = tcx.sess.struct_span_err(
gat_item_hir.span,
- &format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
+ format!("missing required bound{} on `{}`", plural, gat_item_hir.ident),
);
let suggestion = format!(
@@ -453,14 +455,14 @@ fn check_gat_where_clauses(tcx: TyCtxt<'_>, associated_items: &[hir::TraitItemRe
);
err.span_suggestion(
gat_item_hir.generics.tail_span_for_predicate_suggestion(),
- &format!("add the required where clause{plural}"),
+ format!("add the required where clause{plural}"),
suggestion,
Applicability::MachineApplicable,
);
let bound =
if unsatisfied_bounds.len() > 1 { "these bounds are" } else { "this bound is" };
- err.note(&format!(
+ err.note(format!(
"{} currently required to ensure that impls have maximum flexibility",
bound
));
@@ -914,14 +916,14 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) {
if is_ptr {
tcx.sess.span_err(
hir_ty.span,
- &format!(
+ format!(
"using {unsupported_type} as const generic parameters is forbidden",
),
);
} else {
let mut err = tcx.sess.struct_span_err(
hir_ty.span,
- &format!(
+ format!(
"{unsupported_type} is forbidden as the type of a const generic parameter",
),
);
@@ -1025,9 +1027,9 @@ fn check_type_defn<'tcx>(tcx: TyCtxt<'tcx>, item: &hir::Item<'tcx>, all_sized: b
packed && {
let ty = tcx.type_of(variant.fields.raw.last().unwrap().did).subst_identity();
let ty = tcx.erase_regions(ty);
- if ty.needs_infer() {
+ if ty.has_infer() {
tcx.sess
- .delay_span_bug(item.span, &format!("inference variables in {:?}", ty));
+ .delay_span_bug(item.span, format!("inference variables in {:?}", ty));
// Just treat unresolved type expression as if it needs drop.
true
} else {
@@ -1125,7 +1127,7 @@ fn check_associated_type_bounds(wfcx: &WfCheckingCtxt<'_, '_>, item: ty::AssocIt
let bounds = wfcx.tcx().explicit_item_bounds(item.def_id);
debug!("check_associated_type_bounds: bounds={:?}", bounds);
- let wf_obligations = bounds.iter().flat_map(|&(bound, bound_span)| {
+ let wf_obligations = bounds.subst_identity_iter_copied().flat_map(|(bound, bound_span)| {
let normalized_bound = wfcx.normalize(span, None, bound);
traits::wf::predicate_obligations(
wfcx.infcx,
@@ -1290,7 +1292,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// Ignore dependent defaults -- that is, where the default of one type
// parameter includes another (e.g., `<T, U = T>`). In those cases, we can't
// be sure if it will error or not as user might always specify the other.
- if !ty.needs_subst() {
+ if !ty.has_param() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
Some(WellFormedLoc::Ty(param.def_id.expect_local())),
@@ -1306,7 +1308,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
// for `struct Foo<const N: usize, const M: usize = { 1 - 2 }>`
// we should eagerly error.
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
- if !default_ct.needs_subst() {
+ if !default_ct.has_param() {
wfcx.register_wf_obligation(
tcx.def_span(param.def_id),
None,
@@ -1340,7 +1342,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
if is_our_default(param) {
let default_ty = tcx.type_of(param.def_id).subst_identity();
// ... and it's not a dependent default, ...
- if !default_ty.needs_subst() {
+ if !default_ty.has_param() {
// ... then substitute it with the default.
return default_ty.into();
}
@@ -1353,7 +1355,7 @@ fn check_where_clauses<'tcx>(wfcx: &WfCheckingCtxt<'_, 'tcx>, span: Span, def_id
if is_our_default(param) {
let default_ct = tcx.const_param_default(param.def_id).subst_identity();
// ... and it's not a dependent default, ...
- if !default_ct.needs_subst() {
+ if !default_ct.has_param() {
// ... then substitute it with the default.
return default_ct.into();
}
@@ -1574,21 +1576,14 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ImplTraitInTraitFinder<'_, 'tcx> {
&& let hir::OpaqueTyOrigin::FnReturn(source) | hir::OpaqueTyOrigin::AsyncFn(source) = opaque.origin
&& source == self.fn_def_id
{
- let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, depth| {
- if let ty::ReLateBound(index, bv) = re.kind() {
- if depth != ty::INNERMOST {
- return tcx.mk_re_error_with_message(
- DUMMY_SP,
- "we shouldn't walk non-predicate binders with `impl Trait`...",
- );
- }
- tcx.mk_re_late_bound(index.shifted_out_to_binder(self.depth), bv)
- } else {
- re
+ let opaque_ty = tcx.fold_regions(unshifted_opaque_ty, |re, _depth| {
+ match re.kind() {
+ ty::ReEarlyBound(_) | ty::ReFree(_) | ty::ReError(_) => re,
+ r => bug!("unexpected region: {r:?}"),
}
});
for (bound, bound_span) in tcx
- .bound_explicit_item_bounds(opaque_ty.def_id)
+ .explicit_item_bounds(opaque_ty.def_id)
.subst_iter_copied(tcx, opaque_ty.substs)
{
let bound = self.wfcx.normalize(bound_span, None, bound);
@@ -1656,7 +1651,7 @@ fn check_method_receiver<'tcx>(
&tcx.sess.parse_sess,
sym::arbitrary_self_types,
span,
- &format!(
+ format!(
"`{receiver_ty}` cannot be used as the type of `self` without \
the `arbitrary_self_types` feature",
),
@@ -1784,7 +1779,7 @@ fn receiver_is_implemented<'tcx>(
receiver_ty: Ty<'tcx>,
) -> bool {
let tcx = wfcx.tcx();
- let trait_ref = ty::Binder::dummy(tcx.mk_trait_ref(receiver_trait_def_id, [receiver_ty]));
+ let trait_ref = ty::TraitRef::new(tcx, receiver_trait_def_id, [receiver_ty]);
let obligation = traits::Obligation::new(tcx, cause, wfcx.param_env, trait_ref);
@@ -1879,10 +1874,10 @@ fn report_bivariance(
} else {
format!("consider removing `{param_name}` or referring to it in a field")
};
- err.help(&msg);
+ err.help(msg);
if matches!(param.kind, hir::GenericParamKind::Type { .. }) && !has_explicit_bounds {
- err.help(&format!(
+ err.help(format!(
"if you intended `{0}` to be a const parameter, use `const {0}: usize` instead",
param_name
));
diff --git a/compiler/rustc_hir_analysis/src/coherence/builtin.rs b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
index 0f40cca94..a98d8e171 100644
--- a/compiler/rustc_hir_analysis/src/coherence/builtin.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/builtin.rs
@@ -1,9 +1,11 @@
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/codegen.
-use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem};
+use crate::errors::{
+ ConstParamTyImplOnNonAdt, CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem,
+};
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{struct_span_err, MultiSpan};
+use rustc_errors::{struct_span_err, ErrorGuaranteed, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::lang_items::LangItem;
@@ -14,9 +16,11 @@ use rustc_infer::infer::{DefineOpaqueTypes, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::ty::adjustment::CoerceUnsizedInfo;
use rustc_middle::ty::{self, suggest_constraining_type_params, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::Span;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::misc::{
- type_allowed_to_implement_copy, CopyImplementationError, InfringingFieldsReason,
+ type_allowed_to_implement_const_param_ty, type_allowed_to_implement_copy,
+ ConstParamTyImplementationError, CopyImplementationError, InfringingFieldsReason,
};
use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCause};
@@ -27,6 +31,7 @@ pub fn check_trait(tcx: TyCtxt<'_>, trait_def_id: DefId) {
Checker { tcx, trait_def_id }
.check(lang_items.drop_trait(), visit_implementation_of_drop)
.check(lang_items.copy_trait(), visit_implementation_of_copy)
+ .check(lang_items.const_param_ty_trait(), visit_implementation_of_const_param_ty)
.check(lang_items.coerce_unsized_trait(), visit_implementation_of_coerce_unsized)
.check(lang_items.dispatch_from_dyn_trait(), visit_implementation_of_dispatch_from_dyn);
}
@@ -74,120 +79,16 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_copy: self_type={:?} (free)", self_type);
- let span = match tcx.hir().expect_item(impl_did).kind {
- ItemKind::Impl(hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. }) => return,
- ItemKind::Impl(impl_) => impl_.self_ty.span,
- _ => bug!("expected Copy impl item"),
+ let span = match tcx.hir().expect_item(impl_did).expect_impl() {
+ hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+ hir::Impl { self_ty, .. } => self_ty.span,
};
let cause = traits::ObligationCause::misc(span, impl_did);
match type_allowed_to_implement_copy(tcx, param_env, self_type, cause) {
Ok(()) => {}
- Err(CopyImplementationError::InfrigingFields(fields)) => {
- let mut err = struct_span_err!(
- tcx.sess,
- span,
- E0204,
- "the trait `Copy` cannot be implemented for this type"
- );
-
- // We'll try to suggest constraining type parameters to fulfill the requirements of
- // their `Copy` implementation.
- let mut errors: BTreeMap<_, Vec<_>> = Default::default();
- let mut bounds = vec![];
-
- let mut seen_tys = FxHashSet::default();
-
- for (field, ty, reason) in fields {
- // Only report an error once per type.
- if !seen_tys.insert(ty) {
- continue;
- }
-
- let field_span = tcx.def_span(field.did);
- err.span_label(field_span, "this field does not implement `Copy`");
-
- match reason {
- InfringingFieldsReason::Fulfill(fulfillment_errors) => {
- for error in fulfillment_errors {
- let error_predicate = error.obligation.predicate;
- // Only note if it's not the root obligation, otherwise it's trivial and
- // should be self-explanatory (i.e. a field literally doesn't implement Copy).
-
- // FIXME: This error could be more descriptive, especially if the error_predicate
- // contains a foreign type or if it's a deeply nested type...
- if error_predicate != error.root_obligation.predicate {
- errors
- .entry((ty.to_string(), error_predicate.to_string()))
- .or_default()
- .push(error.obligation.cause.span);
- }
- if let ty::PredicateKind::Clause(ty::Clause::Trait(
- ty::TraitPredicate {
- trait_ref,
- polarity: ty::ImplPolarity::Positive,
- ..
- },
- )) = error_predicate.kind().skip_binder()
- {
- let ty = trait_ref.self_ty();
- if let ty::Param(_) = ty.kind() {
- bounds.push((
- format!("{ty}"),
- trait_ref.print_only_trait_path().to_string(),
- Some(trait_ref.def_id),
- ));
- }
- }
- }
- }
- InfringingFieldsReason::Regions(region_errors) => {
- for error in region_errors {
- let ty = ty.to_string();
- match error {
- RegionResolutionError::ConcreteFailure(origin, a, b) => {
- let predicate = format!("{b}: {a}");
- errors
- .entry((ty.clone(), predicate.clone()))
- .or_default()
- .push(origin.span());
- if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
- bounds.push((b.to_string(), a.to_string(), None));
- }
- }
- RegionResolutionError::GenericBoundFailure(origin, a, b) => {
- let predicate = format!("{a}: {b}");
- errors
- .entry((ty.clone(), predicate.clone()))
- .or_default()
- .push(origin.span());
- if let infer::region_constraints::GenericKind::Param(_) = a {
- bounds.push((a.to_string(), b.to_string(), None));
- }
- }
- _ => continue,
- }
- }
- }
- }
- }
- for ((ty, error_predicate), spans) in errors {
- let span: MultiSpan = spans.into();
- err.span_note(
- span,
- &format!("the `Copy` impl for `{}` requires that `{}`", ty, error_predicate),
- );
- }
- suggest_constraining_type_params(
- tcx,
- tcx.hir().get_generics(impl_did).expect("impls always have generics"),
- &mut err,
- bounds.iter().map(|(param, constraint, def_id)| {
- (param.as_str(), constraint.as_str(), *def_id)
- }),
- None,
- );
- err.emit();
+ Err(CopyImplementationError::InfringingFields(fields)) => {
+ infringing_fields_error(tcx, fields, LangItem::Copy, impl_did, span);
}
Err(CopyImplementationError::NotAnAdt) => {
tcx.sess.emit_err(CopyImplOnNonAdt { span });
@@ -198,6 +99,29 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
}
}
+fn visit_implementation_of_const_param_ty(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
+ let self_type = tcx.type_of(impl_did).subst_identity();
+ assert!(!self_type.has_escaping_bound_vars());
+
+ let param_env = tcx.param_env(impl_did);
+
+ let span = match tcx.hir().expect_item(impl_did).expect_impl() {
+ hir::Impl { polarity: hir::ImplPolarity::Negative(_), .. } => return,
+ impl_ => impl_.self_ty.span,
+ };
+
+ let cause = traits::ObligationCause::misc(span, impl_did);
+ match type_allowed_to_implement_const_param_ty(tcx, param_env, self_type, cause) {
+ Ok(()) => {}
+ Err(ConstParamTyImplementationError::InfrigingFields(fields)) => {
+ infringing_fields_error(tcx, fields, LangItem::ConstParamTy, impl_did, span);
+ }
+ Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed) => {
+ tcx.sess.emit_err(ConstParamTyImplOnNonAdt { span });
+ }
+ }
+}
+
fn visit_implementation_of_coerce_unsized(tcx: TyCtxt<'_>, impl_did: LocalDefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}", impl_did);
@@ -289,7 +213,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
for structs containing the field being coerced, \
ZST fields with 1 byte alignment, and nothing else",
)
- .note(&format!(
+ .note(format!(
"extra field `{}` of type `{}` is not allowed",
field.name, ty_a,
))
@@ -317,7 +241,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
for a coercion between structures with a single field \
being coerced",
)
- .note(&format!(
+ .note(format!(
"currently, {} fields need coercions: {}",
coerced_fields.len(),
coerced_fields
@@ -341,10 +265,11 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef
tcx,
cause.clone(),
param_env,
- ty::Binder::dummy(tcx.mk_trait_ref(
+ ty::TraitRef::new(
+ tcx,
dispatch_from_dyn_trait,
[field.ty(tcx, substs_a), field.ty(tcx, substs_b)],
- )),
+ ),
));
}
let errors = ocx.select_all_or_error();
@@ -373,9 +298,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
let coerce_unsized_trait = tcx.require_lang_item(LangItem::CoerceUnsized, Some(span));
- let unsize_trait = tcx.lang_items().require(LangItem::Unsize).unwrap_or_else(|err| {
- tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err.to_string()));
- });
+ let unsize_trait = tcx.require_lang_item(LangItem::Unsize, Some(span));
let source = tcx.type_of(impl_did).subst_identity();
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap().subst_identity();
@@ -545,7 +468,7 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
"`CoerceUnsized` may only be implemented for \
a coercion between structures with one field being coerced",
)
- .note(&format!(
+ .note(format!(
"currently, {} fields need coercions: {}",
diff_fields.len(),
diff_fields
@@ -580,8 +503,12 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
// Register an obligation for `A: Trait<B>`.
let ocx = ObligationCtxt::new(&infcx);
let cause = traits::ObligationCause::misc(span, impl_did);
- let obligation =
- Obligation::new(tcx, cause, param_env, tcx.mk_trait_ref(trait_def_id, [source, target]));
+ let obligation = Obligation::new(
+ tcx,
+ cause,
+ param_env,
+ ty::TraitRef::new(tcx, trait_def_id, [source, target]),
+ );
ocx.register_obligation(obligation);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@@ -594,3 +521,119 @@ pub fn coerce_unsized_info<'tcx>(tcx: TyCtxt<'tcx>, impl_did: LocalDefId) -> Coe
CoerceUnsizedInfo { custom_kind: kind }
}
+
+fn infringing_fields_error(
+ tcx: TyCtxt<'_>,
+ fields: Vec<(&ty::FieldDef, Ty<'_>, InfringingFieldsReason<'_>)>,
+ lang_item: LangItem,
+ impl_did: LocalDefId,
+ impl_span: Span,
+) -> ErrorGuaranteed {
+ let trait_did = tcx.require_lang_item(lang_item, Some(impl_span));
+
+ let trait_name = tcx.def_path_str(trait_did);
+
+ let mut err = struct_span_err!(
+ tcx.sess,
+ impl_span,
+ E0204,
+ "the trait `{trait_name}` cannot be implemented for this type"
+ );
+
+ // We'll try to suggest constraining type parameters to fulfill the requirements of
+ // their `Copy` implementation.
+ let mut errors: BTreeMap<_, Vec<_>> = Default::default();
+ let mut bounds = vec![];
+
+ let mut seen_tys = FxHashSet::default();
+
+ for (field, ty, reason) in fields {
+ // Only report an error once per type.
+ if !seen_tys.insert(ty) {
+ continue;
+ }
+
+ let field_span = tcx.def_span(field.did);
+ err.span_label(field_span, format!("this field does not implement `{trait_name}`"));
+
+ match reason {
+ InfringingFieldsReason::Fulfill(fulfillment_errors) => {
+ for error in fulfillment_errors {
+ let error_predicate = error.obligation.predicate;
+ // Only note if it's not the root obligation, otherwise it's trivial and
+ // should be self-explanatory (i.e. a field literally doesn't implement Copy).
+
+ // FIXME: This error could be more descriptive, especially if the error_predicate
+ // contains a foreign type or if it's a deeply nested type...
+ if error_predicate != error.root_obligation.predicate {
+ errors
+ .entry((ty.to_string(), error_predicate.to_string()))
+ .or_default()
+ .push(error.obligation.cause.span);
+ }
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(ty::TraitPredicate {
+ trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ ..
+ })) = error_predicate.kind().skip_binder()
+ {
+ let ty = trait_ref.self_ty();
+ if let ty::Param(_) = ty.kind() {
+ bounds.push((
+ format!("{ty}"),
+ trait_ref.print_only_trait_path().to_string(),
+ Some(trait_ref.def_id),
+ ));
+ }
+ }
+ }
+ }
+ InfringingFieldsReason::Regions(region_errors) => {
+ for error in region_errors {
+ let ty = ty.to_string();
+ match error {
+ RegionResolutionError::ConcreteFailure(origin, a, b) => {
+ let predicate = format!("{b}: {a}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let ty::RegionKind::ReEarlyBound(ebr) = *b && ebr.has_name() {
+ bounds.push((b.to_string(), a.to_string(), None));
+ }
+ }
+ RegionResolutionError::GenericBoundFailure(origin, a, b) => {
+ let predicate = format!("{a}: {b}");
+ errors
+ .entry((ty.clone(), predicate.clone()))
+ .or_default()
+ .push(origin.span());
+ if let infer::region_constraints::GenericKind::Param(_) = a {
+ bounds.push((a.to_string(), b.to_string(), None));
+ }
+ }
+ _ => continue,
+ }
+ }
+ }
+ }
+ }
+ for ((ty, error_predicate), spans) in errors {
+ let span: MultiSpan = spans.into();
+ err.span_note(
+ span,
+ format!("the `{trait_name}` impl for `{ty}` requires that `{error_predicate}`"),
+ );
+ }
+ suggest_constraining_type_params(
+ tcx,
+ tcx.hir().get_generics(impl_did).expect("impls always have generics"),
+ &mut err,
+ bounds
+ .iter()
+ .map(|(param, constraint, def_id)| (param.as_str(), constraint.as_str(), *def_id)),
+ None,
+ );
+
+ err.emit()
+}
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
index 3d37e0ce0..335590206 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls.rs
@@ -146,7 +146,7 @@ impl<'tcx> InherentCollect<'tcx> {
);
err.help("consider using an extension trait instead");
if let ty::Ref(_, subty, _) = ty.kind() {
- err.note(&format!(
+ err.note(format!(
"you could also try moving the reference to \
uses of `{}` (such as `self`) within the implementation",
subty
diff --git a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
index ad76e2bed..bd6252344 100644
--- a/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/inherent_impls_overlap.rs
@@ -3,7 +3,7 @@ use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::traits::specialization_graph::OverlapMode;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::Symbol;
diff --git a/compiler/rustc_hir_analysis/src/coherence/mod.rs b/compiler/rustc_hir_analysis/src/coherence/mod.rs
index 465e787c9..4524b87a4 100644
--- a/compiler/rustc_hir_analysis/src/coherence/mod.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/mod.rs
@@ -5,9 +5,10 @@
// done by the orphan and overlap modules. Then we build up various
// mappings. That mapping code resides here.
+use crate::errors;
use rustc_errors::{error_code, struct_span_err};
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::sym;
use rustc_trait_selection::traits;
@@ -22,7 +23,7 @@ fn check_impl(tcx: TyCtxt<'_>, impl_def_id: LocalDefId, trait_ref: ty::TraitRef<
debug!(
"(checking implementation) adding impl for trait '{:?}', item '{}'",
trait_ref,
- tcx.def_path_str(impl_def_id.to_def_id())
+ tcx.def_path_str(impl_def_id)
);
// Skip impls where one of the self type is an error type.
@@ -67,13 +68,7 @@ fn enforce_trait_manually_implementable(
tcx.trait_def(trait_def_id).specialization_kind
{
if !tcx.features().specialization && !tcx.features().min_specialization {
- tcx.sess
- .struct_span_err(
- impl_header_span,
- "implementing `rustc_specialization_trait` traits is unstable",
- )
- .help("add `#![feature(min_specialization)]` to the crate attributes to enable")
- .emit();
+ tcx.sess.emit_err(errors::SpecializationTrait { span: impl_header_span });
return;
}
}
diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
index 47c47de8c..23beacd2a 100644
--- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs
+++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs
@@ -6,7 +6,7 @@ use rustc_errors::{struct_span_err, DelayDm};
use rustc_errors::{Diagnostic, ErrorGuaranteed};
use rustc_hir as hir;
use rustc_middle::ty::subst::InternalSubsts;
-use rustc_middle::ty::util::IgnoreRegions;
+use rustc_middle::ty::util::CheckRegions;
use rustc_middle::ty::{
self, AliasKind, ImplPolarity, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor,
@@ -210,6 +210,19 @@ fn do_orphan_check_impl<'tcx>(
NonlocalImpl::DisallowOther,
),
+ // ```
+ // struct S<T>(T);
+ // impl<T: ?Sized> S<T> {
+ // type This = T;
+ // }
+ // impl<T: ?Sized> AutoTrait for S<T>::This {}
+ // ```
+ // FIXME(inherent_associated_types): The example code above currently leads to a cycle
+ ty::Alias(AliasKind::Inherent, _) => (
+ LocalImpl::Disallow { problematic_kind: "associated type" },
+ NonlocalImpl::DisallowOther,
+ ),
+
// type Opaque = impl Trait;
// impl AutoTrait for Opaque {}
ty::Alias(AliasKind::Opaque, _) => (
@@ -372,10 +385,10 @@ fn emit_orphan_check_error<'tcx>(
if is_target_ty {
// Point at `D<A>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(self_ty_span, &msg);
+ err.span_label(self_ty_span, msg);
} else {
// Point at `C<B>` in `impl<A, B> for C<B> in D<A>`
- err.span_label(trait_span, &msg);
+ err.span_label(trait_span, msg);
}
}
err.note("define and implement a trait or new type instead");
@@ -457,7 +470,7 @@ fn emit_newtype_suggestion_for_raw_ptr(
ptr_ty: &ty::TypeAndMut<'_>,
diag: &mut Diagnostic,
) {
- if !self_ty.needs_subst() {
+ if !self_ty.has_param() {
let mut_key = ptr_ty.mutbl.prefix_str();
let msg_sugg = "consider introducing a new wrapper type".to_owned();
let sugg = vec![
@@ -494,7 +507,7 @@ fn lint_auto_trait_impl<'tcx>(
// Impls which completely cover a given root type are fine as they
// disable auto impls entirely. So only lint if the substs
// are not a permutation of the identity substs.
- let Err(arg) = tcx.uses_unique_generic_params(substs, IgnoreRegions::Yes) else {
+ let Err(arg) = tcx.uses_unique_generic_params(substs, CheckRegions::No) else {
// ok
return;
};
@@ -531,15 +544,15 @@ fn lint_auto_trait_impl<'tcx>(
let self_descr = tcx.def_descr(self_type_did);
match arg {
ty::util::NotUniqueParam::DuplicateParam(arg) => {
- lint.note(&format!("`{}` is mentioned multiple times", arg));
+ lint.note(format!("`{}` is mentioned multiple times", arg));
}
ty::util::NotUniqueParam::NotParam(arg) => {
- lint.note(&format!("`{}` is not a generic parameter", arg));
+ lint.note(format!("`{}` is not a generic parameter", arg));
}
}
lint.span_note(
item_span,
- &format!(
+ format!(
"try using the same sequence of generic parameters as the {} definition",
self_descr,
),
diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs
index cbbaf8f85..ca0d5509c 100644
--- a/compiler/rustc_hir_analysis/src/collect.rs
+++ b/compiler/rustc_hir_analysis/src/collect.rs
@@ -28,7 +28,7 @@ use rustc_hir::{GenericParamKind, Node};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::ObligationCause;
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::util::{Discr, IntTypeExt};
use rustc_middle::ty::{self, AdtKind, Const, IsSuggestable, ToPredicate, Ty, TyCtxt};
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -55,7 +55,6 @@ fn collect_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) {
pub fn provide(providers: &mut Providers) {
resolve_bound_vars::provide(providers);
*providers = Providers {
- opt_const_param_of: type_of::opt_const_param_of,
type_of: type_of::type_of,
item_bounds: item_bounds::item_bounds,
explicit_item_bounds: item_bounds::explicit_item_bounds,
@@ -65,8 +64,8 @@ pub fn provide(providers: &mut Providers) {
explicit_predicates_of: predicates_of::explicit_predicates_of,
super_predicates_of: predicates_of::super_predicates_of,
implied_predicates_of: predicates_of::implied_predicates_of,
- super_predicates_that_define_assoc_type:
- predicates_of::super_predicates_that_define_assoc_type,
+ super_predicates_that_define_assoc_item:
+ predicates_of::super_predicates_that_define_assoc_item,
trait_explicit_predicates_and_bounds: predicates_of::trait_explicit_predicates_and_bounds,
type_param_predicates: predicates_of::type_param_predicates,
trait_def,
@@ -74,7 +73,6 @@ pub fn provide(providers: &mut Providers) {
fn_sig,
impl_trait_ref,
impl_polarity,
- is_foreign_item,
generator_kind,
collect_mod_item_types,
is_type_alias_impl_trait,
@@ -387,8 +385,10 @@ impl<'tcx> AstConv<'tcx> for ItemCtxt<'tcx> {
fn ct_infer(&self, ty: Ty<'tcx>, _: Option<&ty::GenericParamDef>, span: Span) -> Const<'tcx> {
let ty = self.tcx.fold_regions(ty, |r, _| match *r {
- ty::ReErased => self.tcx.lifetimes.re_static,
- _ => r,
+ // This is never reached in practice. If it ever is reached,
+ // `ReErased` should be changed to `ReStatic`, and any other region
+ // left alone.
+ r => bug!("unexpected region: {r:?}"),
});
self.tcx().const_error_with_message(ty, span, "bad placeholder constant")
}
@@ -819,7 +819,7 @@ fn convert_variant(
recovered,
adt_kind == AdtKind::Struct && tcx.has_attr(parent_did, sym::non_exhaustive)
|| variant_did
- .map_or(false, |variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
+ .is_some_and(|variant_did| tcx.has_attr(variant_did, sym::non_exhaustive)),
)
}
@@ -1025,7 +1025,7 @@ fn is_suggestable_infer_ty(ty: &hir::Ty<'_>) -> bool {
is_suggestable_infer_ty(ty) || are_suggestable_generic_args(segment.args().args)
}
Path(hir::QPath::Resolved(ty_opt, hir::Path { segments, .. })) => {
- ty_opt.map_or(false, is_suggestable_infer_ty)
+ ty_opt.is_some_and(is_suggestable_infer_ty)
|| segments.iter().any(|segment| are_suggestable_generic_args(segment.args().args))
}
_ => false,
@@ -1147,8 +1147,14 @@ fn infer_return_ty_for_fn_sig<'tcx>(
let mut visitor = HirPlaceholderCollector::default();
visitor.visit_ty(ty);
+
let mut diag = bad_placeholder(tcx, visitor.0, "return type");
let ret_ty = fn_sig.output();
+ // Don't leak types into signatures unless they're nameable!
+ // For example, if a function returns itself, we don't want that
+ // recursive function definition to leak out into the fn sig.
+ let mut should_recover = false;
+
if let Some(ret_ty) = ret_ty.make_suggestable(tcx, false) {
diag.span_suggestion(
ty.span,
@@ -1156,15 +1162,7 @@ fn infer_return_ty_for_fn_sig<'tcx>(
ret_ty,
Applicability::MachineApplicable,
);
- } else if matches!(ret_ty.kind(), ty::FnDef(..))
- && let Some(fn_sig) = ret_ty.fn_sig(tcx).make_suggestable(tcx, false)
- {
- diag.span_suggestion(
- ty.span,
- "replace with the correct return type",
- fn_sig,
- Applicability::MachineApplicable,
- );
+ should_recover = true;
} else if let Some(sugg) = suggest_impl_trait(tcx, ret_ty, ty.span, def_id) {
diag.span_suggestion(
ty.span,
@@ -1182,9 +1180,20 @@ fn infer_return_ty_for_fn_sig<'tcx>(
https://doc.rust-lang.org/book/ch13-01-closures.html",
);
}
- diag.emit();
- ty::Binder::dummy(fn_sig)
+ let guar = diag.emit();
+
+ if should_recover {
+ ty::Binder::dummy(fn_sig)
+ } else {
+ ty::Binder::dummy(tcx.mk_fn_sig(
+ fn_sig.inputs().iter().copied(),
+ tcx.ty_error(guar),
+ fn_sig.c_variadic,
+ fn_sig.unsafety,
+ fn_sig.abi,
+ ))
+ }
}
None => icx.astconv().ty_of_fn(
hir_id,
@@ -1456,13 +1465,6 @@ fn compute_sig_of_foreign_fn_decl<'tcx>(
fty
}
-fn is_foreign_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
- match tcx.hir().get_by_def_id(def_id) {
- Node::ForeignItem(..) => true,
- _ => false,
- }
-}
-
fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorKind> {
match tcx.hir().get_by_def_id(def_id) {
Node::Expr(&rustc_hir::Expr {
@@ -1476,7 +1478,7 @@ fn generator_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::GeneratorK
fn is_type_alias_impl_trait<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> bool {
match tcx.hir().get_by_def_id(def_id) {
Node::Item(hir::Item { kind: hir::ItemKind::OpaqueTy(opaque), .. }) => {
- matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias)
+ matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. })
}
_ => bug!("tried getting opaque_ty_origin for non-opaque: {:?}", def_id),
}
diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
index 119933697..ed60998ec 100644
--- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs
@@ -51,7 +51,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
// of a const parameter type, e.g. `struct Foo<const N: usize, const M: [u8; N]>` is not allowed.
None
} else if tcx.lazy_normalization() {
- if let Some(param_id) = tcx.hir().opt_const_param_default_param_def_id(hir_id) {
+ let parent_node = tcx.hir().get_parent(hir_id);
+ if let Node::Variant(Variant { disr_expr: Some(constant), .. }) = parent_node
+ && constant.hir_id == hir_id
+ {
+ // enum variant discriminants are not allowed to use any kind of generics
+ None
+ } else if let Some(param_id) =
+ tcx.hir().opt_const_param_default_param_def_id(hir_id)
+ {
// If the def_id we are calling generics_of on is an anon ct default i.e:
//
// struct Foo<const N: usize = { .. }>;
@@ -94,15 +102,15 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
has_self: generics.has_self,
has_late_bound_regions: generics.has_late_bound_regions,
};
+ } else {
+ // HACK(eddyb) this provides the correct generics when
+ // `feature(generic_const_expressions)` is enabled, so that const expressions
+ // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
+ //
+ // Note that we do not supply the parent generics when using
+ // `min_const_generics`.
+ Some(parent_def_id.to_def_id())
}
-
- // HACK(eddyb) this provides the correct generics when
- // `feature(generic_const_expressions)` is enabled, so that const expressions
- // used with const generics, e.g. `Foo<{N+1}>`, can work at all.
- //
- // Note that we do not supply the parent generics when using
- // `min_const_generics`.
- Some(parent_def_id.to_def_id())
} else {
let parent_node = tcx.hir().get_parent(hir_id);
match parent_node {
@@ -115,11 +123,6 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
{
Some(parent_def_id.to_def_id())
}
- Node::Variant(Variant { disr_expr: Some(constant), .. })
- if constant.hir_id == hir_id =>
- {
- Some(parent_def_id.to_def_id())
- }
Node::Expr(&Expr { kind: ExprKind::ConstBlock(_), .. }) => {
Some(tcx.typeck_root_def_id(def_id.to_def_id()))
}
@@ -156,7 +159,10 @@ pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics {
}
Some(fn_def_id.to_def_id())
}
- ItemKind::OpaqueTy(hir::OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
+ ItemKind::OpaqueTy(hir::OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
+ ..
+ }) => {
let parent_id = tcx.hir().get_parent_item(hir_id);
assert_ne!(parent_id, hir::CRATE_OWNER_ID);
debug!("generics_of: parent of opaque ty {:?} is {:?}", def_id, parent_id);
diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
index 2e56d2463..948b903e5 100644
--- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
+++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs
@@ -1,5 +1,5 @@
use super::ItemCtxt;
-use crate::astconv::AstConv;
+use crate::astconv::{AstConv, OnlySelfBounds};
use rustc_hir as hir;
use rustc_infer::traits::util;
use rustc_middle::ty::subst::InternalSubsts;
@@ -26,7 +26,7 @@ fn associated_type_bounds<'tcx>(
);
let icx = ItemCtxt::new(tcx, assoc_item_def_id);
- let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
+ let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
// Associated types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
@@ -67,7 +67,7 @@ fn opaque_type_bounds<'tcx>(
) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
ty::print::with_no_queries!({
let icx = ItemCtxt::new(tcx, opaque_def_id);
- let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds);
+ let mut bounds = icx.astconv().compute_bounds(item_ty, ast_bounds, OnlySelfBounds(false));
// Opaque types are implicitly sized unless a `?Sized` bound is found
icx.astconv().add_implicitly_sized(&mut bounds, item_ty, ast_bounds, None, span);
debug!(?bounds);
@@ -79,14 +79,14 @@ fn opaque_type_bounds<'tcx>(
pub(super) fn explicit_item_bounds(
tcx: TyCtxt<'_>,
def_id: LocalDefId,
-) -> &'_ [(ty::Predicate<'_>, Span)] {
+) -> ty::EarlyBinder<&'_ [(ty::Predicate<'_>, Span)]> {
match tcx.opt_rpitit_info(def_id.to_def_id()) {
// RPITIT's bounds are the same as opaque type bounds, but with
// a projection self type.
Some(ty::ImplTraitInTraitData::Trait { opaque_def_id, .. }) => {
let item = tcx.hir().get_by_def_id(opaque_def_id.expect_local()).expect_item();
let opaque_ty = item.expect_opaque_ty();
- return opaque_type_bounds(
+ return ty::EarlyBinder(opaque_type_bounds(
tcx,
opaque_def_id.expect_local(),
opaque_ty.bounds,
@@ -95,7 +95,7 @@ pub(super) fn explicit_item_bounds(
ty::InternalSubsts::identity_for_item(tcx, def_id),
),
item.span,
- );
+ ));
}
// These should have been fed!
Some(ty::ImplTraitInTraitData::Impl { .. }) => unreachable!(),
@@ -103,7 +103,7 @@ pub(super) fn explicit_item_bounds(
}
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().get(hir_id) {
+ let bounds = match tcx.hir().get(hir_id) {
hir::Node::TraitItem(hir::TraitItem {
kind: hir::TraitItemKind::Type(bounds, _),
span,
@@ -123,16 +123,18 @@ pub(super) fn explicit_item_bounds(
opaque_type_bounds(tcx, def_id, bounds, item_ty, *span)
}
_ => bug!("item_bounds called on {:?}", def_id),
- }
+ };
+ ty::EarlyBinder(bounds)
}
pub(super) fn item_bounds(
tcx: TyCtxt<'_>,
def_id: DefId,
) -> ty::EarlyBinder<&'_ ty::List<ty::Predicate<'_>>> {
- let bounds = tcx.mk_predicates_from_iter(util::elaborate(
- tcx,
- tcx.explicit_item_bounds(def_id).iter().map(|&(bound, _span)| bound),
- ));
- ty::EarlyBinder(bounds)
+ tcx.explicit_item_bounds(def_id).map_bound(|bounds| {
+ tcx.mk_predicates_from_iter(util::elaborate(
+ tcx,
+ bounds.iter().map(|&(bound, _span)| bound),
+ ))
+ })
}
diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
index 9358ed612..e5b5dae55 100644
--- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs
@@ -1,4 +1,4 @@
-use crate::astconv::AstConv;
+use crate::astconv::{AstConv, OnlySelfBounds};
use crate::bounds::Bounds;
use crate::collect::ItemCtxt;
use crate::constrained_generic_params as cgp;
@@ -14,9 +14,6 @@ use rustc_middle::ty::{GenericPredicates, ToPredicate};
use rustc_span::symbol::{sym, Ident};
use rustc_span::{Span, DUMMY_SP};
-#[derive(Debug)]
-struct OnlySelfBounds(bool);
-
/// Returns a list of all type predicates (explicit and implicit) for the definition with
/// ID `def_id`. This includes all predicates returned by `predicates_defined_on`, plus
/// `Self: Trait` predicates for traits.
@@ -99,8 +96,9 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
| ItemKind::Struct(_, generics)
| ItemKind::Union(_, generics) => generics,
- ItemKind::Trait(_, _, generics, ..) | ItemKind::TraitAlias(generics, _) => {
- is_trait = Some(ty::TraitRef::identity(tcx, def_id.to_def_id()));
+ ItemKind::Trait(_, _, generics, self_bounds, ..)
+ | ItemKind::TraitAlias(generics, self_bounds) => {
+ is_trait = Some(self_bounds);
generics
}
ItemKind::OpaqueTy(OpaqueTy { generics, .. }) => generics,
@@ -122,10 +120,14 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
// Below we'll consider the bounds on the type parameters (including `Self`)
// and the explicit where-clauses, but to get the full set of predicates
- // on a trait we need to add in the supertrait bounds and bounds found on
- // associated types.
- if let Some(_trait_ref) = is_trait {
- predicates.extend(tcx.implied_predicates_of(def_id).predicates.iter().cloned());
+ // on a trait we must also consider the bounds that follow the trait's name,
+ // like `trait Foo: A + B + C`.
+ if let Some(self_bounds) = is_trait {
+ predicates.extend(
+ icx.astconv()
+ .compute_bounds(tcx.types.self_param, self_bounds, OnlySelfBounds(false))
+ .predicates(),
+ );
}
// In default impls, we can assume that the self type implements
@@ -225,7 +227,13 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen
}
let mut bounds = Bounds::default();
- icx.astconv().add_bounds(ty, bound_pred.bounds.iter(), &mut bounds, bound_vars);
+ icx.astconv().add_bounds(
+ ty,
+ bound_pred.bounds.iter(),
+ &mut bounds,
+ bound_vars,
+ OnlySelfBounds(false),
+ );
predicates.extend(bounds.predicates());
}
@@ -419,6 +427,8 @@ pub(super) fn explicit_predicates_of<'tcx>(
// supertrait).
if let ty::Alias(ty::Projection, projection) = ty.kind() {
projection.substs == trait_identity_substs
+ // FIXME(return_type_notation): This check should be more robust
+ && !tcx.is_impl_trait_in_trait(projection.def_id)
&& tcx.associated_item(projection.def_id).container_id(tcx)
== def_id.to_def_id()
} else {
@@ -557,7 +567,7 @@ pub(super) fn super_predicates_of(
implied_predicates_with_filter(tcx, trait_def_id.to_def_id(), PredicateFilter::SelfOnly)
}
-pub(super) fn super_predicates_that_define_assoc_type(
+pub(super) fn super_predicates_that_define_assoc_item(
tcx: TyCtxt<'_>,
(trait_def_id, assoc_name): (DefId, Ident),
) -> ty::GenericPredicates<'_> {
@@ -608,7 +618,7 @@ pub(super) fn implied_predicates_with_filter(
let (superbounds, where_bounds_that_match) = match filter {
PredicateFilter::All => (
// Convert the bounds that follow the colon (or equal in trait aliases)
- icx.astconv().compute_bounds(self_param_ty, bounds),
+ icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(false)),
// Also include all where clause bounds
icx.type_parameter_bounds_in_generics(
generics,
@@ -620,7 +630,7 @@ pub(super) fn implied_predicates_with_filter(
),
PredicateFilter::SelfOnly => (
// Convert the bounds that follow the colon (or equal in trait aliases)
- icx.astconv().compute_bounds(self_param_ty, bounds),
+ icx.astconv().compute_bounds(self_param_ty, bounds, OnlySelfBounds(true)),
// Include where clause bounds for `Self`
icx.type_parameter_bounds_in_generics(
generics,
@@ -632,7 +642,7 @@ pub(super) fn implied_predicates_with_filter(
),
PredicateFilter::SelfThatDefines(assoc_name) => (
// Convert the bounds that follow the colon (or equal) that reference the associated name
- icx.astconv().compute_bounds_that_match_assoc_type(self_param_ty, bounds, assoc_name),
+ icx.astconv().compute_bounds_that_match_assoc_item(self_param_ty, bounds, assoc_name),
// Include where clause bounds for `Self` that reference the associated name
icx.type_parameter_bounds_in_generics(
generics,
@@ -645,19 +655,19 @@ pub(super) fn implied_predicates_with_filter(
};
// Combine the two lists to form the complete set of superbounds:
- let implied_bounds = &*tcx
- .arena
- .alloc_from_iter(superbounds.predicates().into_iter().chain(where_bounds_that_match));
+ let implied_bounds =
+ &*tcx.arena.alloc_from_iter(superbounds.predicates().chain(where_bounds_that_match));
debug!(?implied_bounds);
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
+ // Now require that immediate supertraits are converted, which will, in
+ // turn, reach indirect supertraits, so we detect cycles now instead of
+ // overflowing during elaboration.
if matches!(filter, PredicateFilter::SelfOnly) {
- // Now require that immediate supertraits are converted,
- // which will, in turn, reach indirect supertraits.
for &(pred, span) in implied_bounds {
debug!("superbound: {:?}", pred);
- if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder() {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(bound)) = pred.kind().skip_binder()
+ && bound.polarity == ty::ImplPolarity::Positive
+ {
tcx.at(span).super_predicates_of(bound.def_id());
}
}
@@ -713,7 +723,7 @@ pub(super) fn type_param_predicates(
| ItemKind::TyAlias(_, generics)
| ItemKind::OpaqueTy(OpaqueTy {
generics,
- origin: hir::OpaqueTyOrigin::TyAlias,
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
})
| ItemKind::Enum(_, generics)
@@ -775,32 +785,35 @@ impl<'tcx> ItemCtxt<'tcx> {
only_self_bounds: OnlySelfBounds,
assoc_name: Option<Ident>,
) -> Vec<(ty::Predicate<'tcx>, Span)> {
- ast_generics
- .predicates
- .iter()
- .filter_map(|wp| match wp {
- hir::WherePredicate::BoundPredicate(bp) => Some(bp),
- _ => None,
- })
- .flat_map(|bp| {
- let bt = if bp.is_param_bound(param_def_id.to_def_id()) {
- Some(ty)
- } else if !only_self_bounds.0 {
- Some(self.to_ty(bp.bounded_ty))
- } else {
- None
- };
- let bvars = self.tcx.late_bound_vars(bp.hir_id);
-
- bp.bounds.iter().filter_map(move |b| bt.map(|bt| (bt, b, bvars))).filter(
- |(_, b, _)| match assoc_name {
- Some(assoc_name) => self.bound_defines_assoc_item(b, assoc_name),
- None => true,
- },
- )
- })
- .flat_map(|(bt, b, bvars)| predicates_from_bound(self, bt, b, bvars))
- .collect()
+ let mut bounds = Bounds::default();
+
+ for predicate in ast_generics.predicates {
+ let hir::WherePredicate::BoundPredicate(predicate) = predicate else {
+ continue;
+ };
+
+ let bound_ty = if predicate.is_param_bound(param_def_id.to_def_id()) {
+ ty
+ } else if !only_self_bounds.0 {
+ self.to_ty(predicate.bounded_ty)
+ } else {
+ continue;
+ };
+
+ let bound_vars = self.tcx.late_bound_vars(predicate.hir_id);
+ self.astconv().add_bounds(
+ bound_ty,
+ predicate.bounds.iter().filter(|bound| {
+ assoc_name
+ .map_or(true, |assoc_name| self.bound_defines_assoc_item(bound, assoc_name))
+ }),
+ &mut bounds,
+ bound_vars,
+ only_self_bounds,
+ );
+ }
+
+ bounds.predicates().collect()
}
#[instrument(level = "trace", skip(self))]
@@ -809,7 +822,7 @@ impl<'tcx> ItemCtxt<'tcx> {
hir::GenericBound::Trait(poly_trait_ref, _) => {
let trait_ref = &poly_trait_ref.trait_ref;
if let Some(trait_did) = trait_ref.trait_def_id() {
- self.tcx.trait_may_define_assoc_type(trait_did, assoc_name)
+ self.tcx.trait_may_define_assoc_item(trait_did, assoc_name)
} else {
false
}
@@ -818,19 +831,3 @@ impl<'tcx> ItemCtxt<'tcx> {
}
}
}
-
-/// Converts a specific `GenericBound` from the AST into a set of
-/// predicates that apply to the self type. A vector is returned
-/// because this can be anywhere from zero predicates (`T: ?Sized` adds no
-/// predicates) to one (`T: Foo`) to many (`T: Bar<X = i32>` adds `T: Bar`
-/// and `<T as Bar>::X == i32`).
-fn predicates_from_bound<'tcx>(
- astconv: &dyn AstConv<'tcx>,
- param_ty: Ty<'tcx>,
- bound: &'tcx hir::GenericBound<'tcx>,
- bound_vars: &'tcx ty::List<ty::BoundVariableKind>,
-) -> Vec<(ty::Predicate<'tcx>, Span)> {
- let mut bounds = Bounds::default();
- astconv.add_bounds(param_ty, [bound].into_iter(), &mut bounds, bound_vars);
- bounds.predicates().collect()
-}
diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
index e758fe95d..794812a5c 100644
--- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
+++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs
@@ -17,6 +17,7 @@ use rustc_hir::{GenericArg, GenericParam, GenericParamKind, HirIdMap, LifetimeNa
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::*;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeSuperVisitable, TypeVisitor};
use rustc_session::lint;
use rustc_span::def_id::DefId;
@@ -232,8 +233,8 @@ impl<'a> fmt::Debug for TruncatedScopeDebug<'a> {
type ScopeRef<'a> = &'a Scope<'a>;
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers {
resolve_bound_vars,
named_variable_map: |tcx, id| tcx.resolve_bound_vars(id).defs.get(&id),
@@ -455,13 +456,9 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
.collect::<Vec<_>>();
if !infer_spans.is_empty() {
- self.tcx.sess
- .struct_span_err(
- infer_spans,
- "implicit types in closure signatures are forbidden when `for<...>` is present",
- )
- .span_label(for_sp, "`for<...>` is here")
- .emit();
+ self.tcx
+ .sess
+ .emit_err(errors::ClosureImplicitHrtb { spans: infer_spans, for_sp });
}
}
@@ -530,7 +527,8 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
});
}
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::TyAlias, ..
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
+ ..
}) => {
// Opaque types are visited when we visit the
// `TyKind::OpaqueDef`, so that they have the lifetimes from
@@ -711,7 +709,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
let opaque_ty = self.tcx.hir().item(item_id);
match &opaque_ty.kind {
hir::ItemKind::OpaqueTy(hir::OpaqueTy {
- origin: hir::OpaqueTyOrigin::TyAlias,
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
..
}) => {
intravisit::walk_ty(self, ty);
@@ -991,7 +989,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> {
lifetime.ident
),
|lint| {
- let help = &format!(
+ let help = format!(
"you can use the `'static` lifetime directly, in place of `{}`",
lifetime.ident,
);
@@ -1333,7 +1331,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
// We may fail to resolve higher-ranked lifetimes that are mentioned by APIT.
// AST-based resolution does not care for impl-trait desugaring, which are the
- // responibility of lowering. This may create a mismatch between the resolution
+ // responsibility of lowering. This may create a mismatch between the resolution
// AST found (`region_def_id`) which points to HRTB, and what HIR allows.
// ```
// fn foo(x: impl for<'a> Trait<'a, Assoc = impl Copy + 'a>) {}
@@ -1369,7 +1367,7 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
self.tcx.sess.delay_span_bug(
lifetime_ref.ident.span,
- &format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
+ format!("Could not resolve {:?} in scope {:#?}", lifetime_ref, self.scope,),
);
}
@@ -1656,17 +1654,16 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
if binding.gen_args.parenthesized == hir::GenericArgsParentheses::ReturnTypeNotation {
let bound_vars = if let Some(type_def_id) = type_def_id
&& self.tcx.def_kind(type_def_id) == DefKind::Trait
- // FIXME(return_type_notation): We could bound supertrait methods.
- && let Some(assoc_fn) = self
- .tcx
- .associated_items(type_def_id)
- .find_by_name_and_kind(self.tcx, binding.ident, ty::AssocKind::Fn, type_def_id)
+ && let Some((mut bound_vars, assoc_fn)) =
+ BoundVarContext::supertrait_hrtb_vars(
+ self.tcx,
+ type_def_id,
+ binding.ident,
+ ty::AssocKind::Fn,
+ )
{
- self.tcx
- .generics_of(assoc_fn.def_id)
- .params
- .iter()
- .map(|param| match param.kind {
+ bound_vars.extend(self.tcx.generics_of(assoc_fn.def_id).params.iter().map(
+ |param| match param.kind {
ty::GenericParamDefKind::Lifetime => ty::BoundVariableKind::Region(
ty::BoundRegionKind::BrNamed(param.def_id, param.name),
),
@@ -1674,9 +1671,11 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
ty::BoundTyKind::Param(param.def_id, param.name),
),
ty::GenericParamDefKind::Const { .. } => ty::BoundVariableKind::Const,
- })
- .chain(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars())
- .collect()
+ },
+ ));
+ bound_vars
+ .extend(self.tcx.fn_sig(assoc_fn.def_id).subst_identity().bound_vars());
+ bound_vars
} else {
self.tcx.sess.delay_span_bug(
binding.ident.span,
@@ -1693,8 +1692,13 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
});
});
} else if let Some(type_def_id) = type_def_id {
- let bound_vars =
- BoundVarContext::supertrait_hrtb_vars(self.tcx, type_def_id, binding.ident);
+ let bound_vars = BoundVarContext::supertrait_hrtb_vars(
+ self.tcx,
+ type_def_id,
+ binding.ident,
+ ty::AssocKind::Type,
+ )
+ .map(|(bound_vars, _)| bound_vars);
self.with(scope, |this| {
let scope = Scope::Supertrait {
bound_vars: bound_vars.unwrap_or_default(),
@@ -1724,11 +1728,15 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
def_id: DefId,
assoc_name: Ident,
- ) -> Option<Vec<ty::BoundVariableKind>> {
- let trait_defines_associated_type_named = |trait_def_id: DefId| {
- tcx.associated_items(trait_def_id)
- .find_by_name_and_kind(tcx, assoc_name, ty::AssocKind::Type, trait_def_id)
- .is_some()
+ assoc_kind: ty::AssocKind,
+ ) -> Option<(Vec<ty::BoundVariableKind>, &'tcx ty::AssocItem)> {
+ let trait_defines_associated_item_named = |trait_def_id: DefId| {
+ tcx.associated_items(trait_def_id).find_by_name_and_kind(
+ tcx,
+ assoc_name,
+ assoc_kind,
+ trait_def_id,
+ )
};
use smallvec::{smallvec, SmallVec};
@@ -1746,10 +1754,10 @@ impl<'a, 'tcx> BoundVarContext<'a, 'tcx> {
_ => break None,
}
- if trait_defines_associated_type_named(def_id) {
- break Some(bound_vars.into_iter().collect());
+ if let Some(assoc_item) = trait_defines_associated_item_named(def_id) {
+ break Some((bound_vars.into_iter().collect(), assoc_item));
}
- let predicates = tcx.super_predicates_that_define_assoc_type((def_id, assoc_name));
+ let predicates = tcx.super_predicates_that_define_assoc_item((def_id, assoc_name));
let obligations = predicates.predicates.iter().filter_map(|&(pred, _)| {
let bound_predicate = pred.kind();
match bound_predicate.skip_binder() {
@@ -1917,7 +1925,7 @@ fn is_late_bound_map(
/// handles cycle detection as we go through the query system.
///
/// This is necessary in the first place for the following case:
- /// ```
+ /// ```rust,ignore (pseudo-Rust)
/// type Alias<'a, T> = <T as Trait<'a>>::Assoc;
/// fn foo<'a>(_: Alias<'a, ()>) -> Alias<'a, ()> { ... }
/// ```
@@ -1942,7 +1950,7 @@ fn is_late_bound_map(
ty::Param(param_ty) => {
self.arg_is_constrained[param_ty.index as usize] = true;
}
- ty::Alias(ty::Projection, _) => return ControlFlow::Continue(()),
+ ty::Alias(ty::Projection | ty::Inherent, _) => return ControlFlow::Continue(()),
_ => (),
}
t.super_visit_with(self)
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs
index c173bd913..8e082d3c5 100644
--- a/compiler/rustc_hir_analysis/src/collect/type_of.rs
+++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs
@@ -1,10 +1,7 @@
use rustc_errors::{Applicability, StashKey};
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_hir::intravisit;
-use rustc_hir::intravisit::Visitor;
-use rustc_hir::{HirId, Node};
-use rustc_middle::hir::nested_filter;
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::HirId;
use rustc_middle::ty::print::with_forced_trimmed_paths;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::util::IntTypeExt;
@@ -14,24 +11,84 @@ use rustc_span::{Span, DUMMY_SP};
use super::ItemCtxt;
use super::{bad_placeholder, is_suggestable_infer_ty};
-use crate::errors::UnconstrainedOpaqueType;
-/// Computes the relevant generic parameter for a potential generic const argument.
-///
-/// This should be called using the query `tcx.opt_const_param_of`.
-pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<DefId> {
+mod opaque;
+
+fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> {
use hir::*;
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- match tcx.hir().get(hir_id) {
- Node::AnonConst(_) => (),
- _ => return None,
- };
+ let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() };
let parent_node_id = tcx.hir().parent_id(hir_id);
let parent_node = tcx.hir().get(parent_node_id);
let (generics, arg_idx) = match parent_node {
+ // Easy case: arrays repeat expressions.
+ Node::Ty(&Ty { kind: TyKind::Array(_, ref constant), .. })
+ | Node::Expr(&Expr { kind: ExprKind::Repeat(_, ref constant), .. })
+ if constant.hir_id() == hir_id =>
+ {
+ return tcx.types.usize
+ }
+ Node::Ty(&Ty { kind: TyKind::Typeof(ref e), .. }) if e.hir_id == hir_id => {
+ return tcx.typeck(def_id).node_type(e.hir_id)
+ }
+ Node::Expr(&Expr { kind: ExprKind::ConstBlock(ref anon_const), .. })
+ if anon_const.hir_id == hir_id =>
+ {
+ let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id());
+ return substs.as_inline_const().ty()
+ }
+ Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
+ | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
+ if asm.operands.iter().any(|(op, _op_sp)| match op {
+ hir::InlineAsmOperand::Const { anon_const }
+ | hir::InlineAsmOperand::SymFn { anon_const } => anon_const.hir_id == hir_id,
+ _ => false,
+ }) =>
+ {
+ return tcx.typeck(def_id).node_type(hir_id)
+ }
+ Node::Variant(Variant { disr_expr: Some(ref e), .. }) if e.hir_id == hir_id => {
+ return tcx
+ .adt_def(tcx.hir().get_parent_item(hir_id))
+ .repr()
+ .discr_type()
+ .to_ty(tcx)
+ }
+ Node::GenericParam(&GenericParam {
+ def_id: param_def_id,
+ kind: GenericParamKind::Const { default: Some(ct), .. },
+ ..
+ }) if ct.hir_id == hir_id => {
+ return tcx.type_of(param_def_id)
+ .no_bound_vars()
+ .expect("const parameter types cannot be generic")
+ }
+
+ Node::TypeBinding(binding @ &TypeBinding { hir_id: binding_id, .. })
+ if let Node::TraitRef(trait_ref) = tcx.hir().get(
+ tcx.hir().parent_id(binding_id)
+ ) =>
+ {
+ let Some(trait_def_id) = trait_ref.trait_def_id() else {
+ return tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find trait");
+ };
+ let assoc_items = tcx.associated_items(trait_def_id);
+ let assoc_item = assoc_items.find_by_name_and_kind(
+ tcx, binding.ident, ty::AssocKind::Const, def_id.to_def_id(),
+ );
+ return if let Some(assoc_item) = assoc_item {
+ tcx.type_of(assoc_item.def_id)
+ .no_bound_vars()
+ .expect("const parameter types cannot be generic")
+ } else {
+ // FIXME(associated_const_equality): add a useful error message here.
+ tcx.ty_error_with_message(tcx.def_span(def_id), "Could not find associated const on trait")
+ }
+ }
+
// This match arm is for when the def_id appears in a GAT whose
// path can't be resolved without typechecking e.g.
//
@@ -68,7 +125,7 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// the def_id that this query was called with. We filter to only type and const args here
// as a precaution for if it's ever allowed to elide lifetimes in GAT's. It currently isn't
// but it can't hurt to be safe ^^
- if let ty::Alias(ty::Projection, projection) = ty.kind() {
+ if let ty::Alias(ty::Projection | ty::Inherent, projection) = ty.kind() {
let generics = tcx.generics_of(projection.def_id);
let arg_index = segment
@@ -86,11 +143,10 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
(generics, arg_index)
} else {
// I dont think it's possible to reach this but I'm not 100% sure - BoxyUwU
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
tcx.def_span(def_id),
"unexpected non-GAT usage of an anon const",
);
- return None;
}
}
Node::Expr(&Expr {
@@ -103,7 +159,12 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
// This may fail in case the method/path does not actually exist.
// As there is no relevant param for `def_id`, we simply return
// `None` here.
- let type_dependent_def = tables.type_dependent_def_id(parent_node_id)?;
+ let Some(type_dependent_def) = tables.type_dependent_def_id(parent_node_id) else {
+ return tcx.ty_error_with_message(
+ tcx.def_span(def_id),
+ format!("unable to find type-dependent def for {:?}", parent_node_id),
+ );
+ };
let idx = segment
.args
.and_then(|args| {
@@ -140,19 +201,17 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
if let Some(path) = get_path_containing_arg_in_pat(pat, hir_id) {
path
} else {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
tcx.def_span(def_id),
- &format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
+ format!("unable to find const parent for {} in pat {:?}", hir_id, pat),
);
- return None;
}
}
_ => {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
tcx.def_span(def_id),
- &format!("unexpected const parent path {:?}", parent_node),
+ format!("unexpected const parent path {:?}", parent_node),
);
- return None;
}
};
@@ -171,32 +230,34 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
.position(|ct| ct.hir_id == hir_id)
.map(|idx| (idx, seg)))
}) else {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
tcx.def_span(def_id),
"no arg matching AnonConst in path",
);
- return None;
};
let generics = match tcx.res_generics_def_id(segment.res) {
Some(def_id) => tcx.generics_of(def_id),
None => {
- tcx.sess.delay_span_bug(
+ return tcx.ty_error_with_message(
tcx.def_span(def_id),
- &format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
+ format!("unexpected anon const res {:?} in path: {:?}", segment.res, path),
);
- return None;
}
};
(generics, arg_index)
}
- _ => return None,
+
+ _ => return tcx.ty_error_with_message(
+ tcx.def_span(def_id),
+ format!("unexpected const parent in type_of(): {parent_node:?}"),
+ ),
};
debug!(?parent_node);
debug!(?generics, ?arg_idx);
- generics
+ if let Some(param_def_id) = generics
.params
.iter()
.filter(|param| param.kind.is_ty_or_const())
@@ -211,6 +272,14 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<
}
_ => None,
})
+ {
+ tcx.type_of(param_def_id).no_bound_vars().expect("const parameter types cannot be generic")
+ } else {
+ return tcx.ty_error_with_message(
+ tcx.def_span(def_id),
+ format!("const generic parameter not found in {generics:?} at position {arg_idx:?}"),
+ );
+ }
}
fn get_path_containing_arg_in_pat<'hir>(
@@ -251,7 +320,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
match tcx.collect_return_position_impl_trait_in_trait_tys(fn_def_id) {
Ok(map) => {
let assoc_item = tcx.associated_item(def_id);
- return ty::EarlyBinder(map[&assoc_item.trait_item_def_id.unwrap()]);
+ return map[&assoc_item.trait_item_def_id.unwrap()];
}
Err(_) => {
return ty::EarlyBinder(tcx.ty_error_with_message(
@@ -355,9 +424,10 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
let substs = InternalSubsts::identity_for_item(tcx, def_id);
tcx.mk_adt(def, substs)
}
- ItemKind::OpaqueTy(OpaqueTy { origin: hir::OpaqueTyOrigin::TyAlias, .. }) => {
- find_opaque_ty_constraints_for_tait(tcx, def_id)
- }
+ ItemKind::OpaqueTy(OpaqueTy {
+ origin: hir::OpaqueTyOrigin::TyAlias { .. },
+ ..
+ }) => opaque::find_opaque_ty_constraints_for_tait(tcx, def_id),
// Opaque types desugared from `impl Trait`.
ItemKind::OpaqueTy(OpaqueTy {
origin:
@@ -371,7 +441,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
"tried to get type of this RPITIT with no definition"
);
}
- find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
+ opaque::find_opaque_ty_constraints_for_rpit(tcx, def_id, owner)
}
ItemKind::Trait(..)
| ItemKind::TraitAlias(..)
@@ -415,143 +485,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
tcx.typeck(def_id).node_type(hir_id)
}
- Node::AnonConst(_) if let Some(param) = tcx.opt_const_param_of(def_id) => {
- // We defer to `type_of` of the corresponding parameter
- // for generic arguments.
- tcx.type_of(param).subst_identity()
- }
-
- Node::AnonConst(_) => {
- let parent_node = tcx.hir().get_parent(hir_id);
- match parent_node {
- Node::Ty(Ty { kind: TyKind::Array(_, constant), .. })
- | Node::Expr(Expr { kind: ExprKind::Repeat(_, constant), .. })
- if constant.hir_id() == hir_id =>
- {
- tcx.types.usize
- }
- Node::Ty(Ty { kind: TyKind::Typeof(e), .. }) if e.hir_id == hir_id => {
- tcx.typeck(def_id).node_type(e.hir_id)
- }
-
- Node::Expr(Expr { kind: ExprKind::ConstBlock(anon_const), .. })
- if anon_const.hir_id == hir_id =>
- {
- let substs = InternalSubsts::identity_for_item(tcx, def_id);
- substs.as_inline_const().ty()
- }
-
- Node::Expr(&Expr { kind: ExprKind::InlineAsm(asm), .. })
- | Node::Item(&Item { kind: ItemKind::GlobalAsm(asm), .. })
- if asm.operands.iter().any(|(op, _op_sp)| match op {
- hir::InlineAsmOperand::Const { anon_const }
- | hir::InlineAsmOperand::SymFn { anon_const } => {
- anon_const.hir_id == hir_id
- }
- _ => false,
- }) =>
- {
- tcx.typeck(def_id).node_type(hir_id)
- }
-
- Node::Variant(Variant { disr_expr: Some(e), .. }) if e.hir_id == hir_id => {
- tcx.adt_def(tcx.hir().get_parent_item(hir_id)).repr().discr_type().to_ty(tcx)
- }
-
- Node::TypeBinding(TypeBinding {
- hir_id: binding_id,
- kind: TypeBindingKind::Equality { term: Term::Const(e) },
- ident,
- ..
- }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
- && e.hir_id == hir_id =>
- {
- let Some(trait_def_id) = trait_ref.trait_def_id() else {
- return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
- };
- let assoc_items = tcx.associated_items(trait_def_id);
- let assoc_item = assoc_items.find_by_name_and_kind(
- tcx,
- *ident,
- ty::AssocKind::Const,
- def_id.to_def_id(),
- );
- if let Some(assoc_item) = assoc_item {
- tcx.type_of(assoc_item.def_id)
- .no_bound_vars()
- .expect("const parameter types cannot be generic")
- } else {
- // FIXME(associated_const_equality): add a useful error message here.
- tcx.ty_error_with_message(
- DUMMY_SP,
- "Could not find associated const on trait",
- )
- }
- }
-
- Node::TypeBinding(TypeBinding {
- hir_id: binding_id,
- gen_args,
- kind,
- ident,
- ..
- }) if let Node::TraitRef(trait_ref) = tcx.hir().get_parent(*binding_id)
- && let Some((idx, _)) =
- gen_args.args.iter().enumerate().find(|(_, arg)| {
- if let GenericArg::Const(ct) = arg {
- ct.value.hir_id == hir_id
- } else {
- false
- }
- }) =>
- {
- let Some(trait_def_id) = trait_ref.trait_def_id() else {
- return ty::EarlyBinder(tcx.ty_error_with_message(DUMMY_SP, "Could not find trait"));
- };
- let assoc_items = tcx.associated_items(trait_def_id);
- let assoc_item = assoc_items.find_by_name_and_kind(
- tcx,
- *ident,
- match kind {
- // I think `<A: T>` type bindings requires that `A` is a type
- TypeBindingKind::Constraint { .. }
- | TypeBindingKind::Equality { term: Term::Ty(..) } => {
- ty::AssocKind::Type
- }
- TypeBindingKind::Equality { term: Term::Const(..) } => {
- ty::AssocKind::Const
- }
- },
- def_id.to_def_id(),
- );
- if let Some(assoc_item) = assoc_item
- && let param = &tcx.generics_of(assoc_item.def_id).params[idx]
- && matches!(param.kind, ty::GenericParamDefKind::Const { .. })
- {
- tcx.type_of(param.def_id)
- .no_bound_vars()
- .expect("const parameter types cannot be generic")
- } else {
- // FIXME(associated_const_equality): add a useful error message here.
- tcx.ty_error_with_message(
- DUMMY_SP,
- "Could not find const param on associated item",
- )
- }
- }
-
- Node::GenericParam(&GenericParam {
- def_id: param_def_id,
- kind: GenericParamKind::Const { default: Some(ct), .. },
- ..
- }) if ct.hir_id == hir_id => tcx.type_of(param_def_id).subst_identity(),
-
- x => tcx.ty_error_with_message(
- DUMMY_SP,
- &format!("unexpected const parent in type_of(): {x:?}"),
- ),
- }
- }
+ Node::AnonConst(_) => anon_const_type_of(tcx, def_id),
Node::GenericParam(param) => match &param.kind {
GenericParamKind::Type { default: Some(ty), .. }
@@ -566,303 +500,6 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder<Ty
ty::EarlyBinder(output)
}
-#[instrument(skip(tcx), level = "debug")]
-/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
-/// laid for "higher-order pattern unification".
-/// This ensures that inference is tractable.
-/// In particular, definitions of opaque types can only use other generics as arguments,
-/// and they cannot repeat an argument. Example:
-///
-/// ```ignore (illustrative)
-/// type Foo<A, B> = impl Bar<A, B>;
-///
-/// // Okay -- `Foo` is applied to two distinct, generic types.
-/// fn a<T, U>() -> Foo<T, U> { .. }
-///
-/// // Not okay -- `Foo` is applied to `T` twice.
-/// fn b<T>() -> Foo<T, T> { .. }
-///
-/// // Not okay -- `Foo` is applied to a non-generic type.
-/// fn b<T>() -> Foo<T, u32> { .. }
-/// ```
-///
-fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
- use rustc_hir::{Expr, ImplItem, Item, TraitItem};
-
- struct ConstraintLocator<'tcx> {
- tcx: TyCtxt<'tcx>,
-
- /// def_id of the opaque type whose defining uses are being checked
- def_id: LocalDefId,
-
- /// as we walk the defining uses, we are checking that all of them
- /// define the same hidden type. This variable is set to `Some`
- /// with the first type that we find, and then later types are
- /// checked against it (we also carry the span of that first
- /// type).
- found: Option<ty::OpaqueHiddenType<'tcx>>,
-
- /// In the presence of dead code, typeck may figure out a hidden type
- /// while borrowck will not. We collect these cases here and check at
- /// the end that we actually found a type that matches (modulo regions).
- typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
- }
-
- impl ConstraintLocator<'_> {
- #[instrument(skip(self), level = "debug")]
- fn check(&mut self, item_def_id: LocalDefId) {
- // Don't try to check items that cannot possibly constrain the type.
- if !self.tcx.has_typeck_results(item_def_id) {
- debug!("no constraint: no typeck results");
- return;
- }
- // Calling `mir_borrowck` can lead to cycle errors through
- // const-checking, avoid calling it if we don't have to.
- // ```rust
- // type Foo = impl Fn() -> usize; // when computing type for this
- // const fn bar() -> Foo {
- // || 0usize
- // }
- // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
- // // because we again need to reveal `Foo` so we can check whether the
- // // constant does not contain interior mutability.
- // ```
- let tables = self.tcx.typeck(item_def_id);
- if let Some(guar) = tables.tainted_by_errors {
- self.found =
- Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
- return;
- }
- let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
- debug!("no constraints in typeck results");
- return;
- };
- if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
- self.typeck_types.push(typeck_hidden_ty);
- }
-
- // Use borrowck to get the type with unerased regions.
- let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
- debug!(?concrete_opaque_types);
- if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
- debug!(?concrete_type, "found constraint");
- if let Some(prev) = &mut self.found {
- if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
- let guar = prev.report_mismatch(&concrete_type, self.tcx);
- prev.ty = self.tcx.ty_error(guar);
- }
- } else {
- self.found = Some(concrete_type);
- }
- }
- }
- }
-
- impl<'tcx> intravisit::Visitor<'tcx> for ConstraintLocator<'tcx> {
- type NestedFilter = nested_filter::All;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
- fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure(closure) = ex.kind {
- self.check(closure.def_id);
- }
- intravisit::walk_expr(self, ex);
- }
- fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_item(self, it);
- }
- }
- fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_impl_item(self, it);
- }
- }
- fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.owner_id);
- self.check(it.owner_id.def_id);
- intravisit::walk_trait_item(self, it);
- }
- }
-
- let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
- let scope = tcx.hir().get_defining_scope(hir_id);
- let mut locator = ConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
-
- debug!(?scope);
-
- if scope == hir::CRATE_HIR_ID {
- tcx.hir().walk_toplevel_module(&mut locator);
- } else {
- trace!("scope={:#?}", tcx.hir().get(scope));
- match tcx.hir().get(scope) {
- // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
- // This allows our visitor to process the defining item itself, causing
- // it to pick up any 'sibling' defining uses.
- //
- // For example, this code:
- // ```
- // fn foo() {
- // type Blah = impl Debug;
- // let my_closure = || -> Blah { true };
- // }
- // ```
- //
- // requires us to explicitly process `foo()` in order
- // to notice the defining usage of `Blah`.
- Node::Item(it) => locator.visit_item(it),
- Node::ImplItem(it) => locator.visit_impl_item(it),
- Node::TraitItem(it) => locator.visit_trait_item(it),
- other => bug!("{:?} is not a valid scope for an opaque type item", other),
- }
- }
-
- let Some(hidden) = locator.found else {
- 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) {
- _ if scope == hir::CRATE_HIR_ID => "module",
- Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
- Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
- _ => "item",
- },
- });
- return tcx.ty_error(reported);
- };
-
- // Only check against typeck if we didn't already error
- if !hidden.ty.references_error() {
- for concrete_type in locator.typeck_types {
- if tcx.erase_regions(concrete_type.ty) != tcx.erase_regions(hidden.ty)
- && !(concrete_type, hidden).references_error()
- {
- hidden.report_mismatch(&concrete_type, tcx);
- }
- }
- }
-
- hidden.ty
-}
-
-fn find_opaque_ty_constraints_for_rpit(
- tcx: TyCtxt<'_>,
- def_id: LocalDefId,
- owner_def_id: LocalDefId,
-) -> Ty<'_> {
- use rustc_hir::{Expr, ImplItem, Item, TraitItem};
-
- struct ConstraintChecker<'tcx> {
- tcx: TyCtxt<'tcx>,
-
- /// def_id of the opaque type whose defining uses are being checked
- def_id: LocalDefId,
-
- found: ty::OpaqueHiddenType<'tcx>,
- }
-
- impl ConstraintChecker<'_> {
- #[instrument(skip(self), level = "debug")]
- fn check(&self, def_id: LocalDefId) {
- // Use borrowck to get the type with unerased regions.
- let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
- debug!(?concrete_opaque_types);
- for (&def_id, &concrete_type) in concrete_opaque_types {
- if def_id != self.def_id {
- // Ignore constraints for other opaque types.
- continue;
- }
-
- debug!(?concrete_type, "found constraint");
-
- if concrete_type.ty != self.found.ty
- && !(concrete_type, self.found).references_error()
- {
- self.found.report_mismatch(&concrete_type, self.tcx);
- }
- }
- }
- }
-
- impl<'tcx> intravisit::Visitor<'tcx> for ConstraintChecker<'tcx> {
- type NestedFilter = nested_filter::OnlyBodies;
-
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
- fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
- if let hir::ExprKind::Closure(closure) = ex.kind {
- self.check(closure.def_id);
- }
- intravisit::walk_expr(self, ex);
- }
- fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
- trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_item(self, it);
- }
- }
- fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
- trace!(?it.owner_id);
- // The opaque type itself or its children are not within its reveal scope.
- if it.owner_id.def_id != self.def_id {
- self.check(it.owner_id.def_id);
- intravisit::walk_impl_item(self, it);
- }
- }
- fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
- trace!(?it.owner_id);
- self.check(it.owner_id.def_id);
- intravisit::walk_trait_item(self, it);
- }
- }
-
- let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
-
- if let Some(concrete) = concrete {
- let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
- debug!(?scope);
- let mut locator = ConstraintChecker { def_id, tcx, found: concrete };
-
- match tcx.hir().get(scope) {
- Node::Item(it) => intravisit::walk_item(&mut locator, it),
- Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
- Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
- other => bug!("{:?} is not a valid scope for an opaque type item", other),
- }
- }
-
- concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
- let table = tcx.typeck(owner_def_id);
- if let Some(guar) = table.tainted_by_errors {
- // Some error in the
- // owner fn prevented us from populating
- // the `concrete_opaque_types` table.
- tcx.ty_error(guar)
- } else {
- table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
- // We failed to resolve the opaque type or it
- // resolves to itself. We interpret this as the
- // no values of the hidden type ever being constructed,
- // so we can just make the hidden type be `!`.
- // For backwards compatibility reasons, we fall back to
- // `()` until we the diverging default is changed.
- tcx.mk_diverging_default()
- })
- }
- })
-}
-
fn infer_placeholder_type<'a>(
tcx: TyCtxt<'a>,
def_id: LocalDefId,
@@ -893,14 +530,14 @@ fn infer_placeholder_type<'a>(
if let Some(ty) = ty.make_suggestable(tcx, false) {
err.span_suggestion(
span,
- &format!("provide a type for the {item}", item = kind),
+ format!("provide a type for the {item}", item = kind),
format!("{colon} {ty}"),
Applicability::MachineApplicable,
);
} else {
with_forced_trimmed_paths!(err.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{ty}` cannot be named"),
+ format!("however, the inferred type `{ty}` cannot be named"),
));
}
}
@@ -921,7 +558,7 @@ fn infer_placeholder_type<'a>(
} else {
with_forced_trimmed_paths!(diag.span_note(
tcx.hir().body(body_id).value.span,
- &format!("however, the inferred type `{ty}` cannot be named"),
+ format!("however, the inferred type `{ty}` cannot be named"),
));
}
}
diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
new file mode 100644
index 000000000..f7c5b4467
--- /dev/null
+++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs
@@ -0,0 +1,298 @@
+use rustc_hir::def_id::LocalDefId;
+use rustc_hir::intravisit::{self, Visitor};
+use rustc_hir::{self as hir, Expr, ImplItem, Item, Node, TraitItem};
+use rustc_middle::hir::nested_filter;
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::DUMMY_SP;
+
+use crate::errors::UnconstrainedOpaqueType;
+
+/// Checks "defining uses" of opaque `impl Trait` types to ensure that they meet the restrictions
+/// laid for "higher-order pattern unification".
+/// This ensures that inference is tractable.
+/// In particular, definitions of opaque types can only use other generics as arguments,
+/// and they cannot repeat an argument. Example:
+///
+/// ```ignore (illustrative)
+/// type Foo<A, B> = impl Bar<A, B>;
+///
+/// // Okay -- `Foo` is applied to two distinct, generic types.
+/// fn a<T, U>() -> Foo<T, U> { .. }
+///
+/// // Not okay -- `Foo` is applied to `T` twice.
+/// fn b<T>() -> Foo<T, T> { .. }
+///
+/// // Not okay -- `Foo` is applied to a non-generic type.
+/// fn b<T>() -> Foo<T, u32> { .. }
+/// ```
+#[instrument(skip(tcx), level = "debug")]
+pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> {
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
+ let scope = tcx.hir().get_defining_scope(hir_id);
+ let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] };
+
+ debug!(?scope);
+
+ if scope == hir::CRATE_HIR_ID {
+ tcx.hir().walk_toplevel_module(&mut locator);
+ } else {
+ trace!("scope={:#?}", tcx.hir().get(scope));
+ match tcx.hir().get(scope) {
+ // We explicitly call `visit_*` methods, instead of using `intravisit::walk_*` methods
+ // This allows our visitor to process the defining item itself, causing
+ // it to pick up any 'sibling' defining uses.
+ //
+ // For example, this code:
+ // ```
+ // fn foo() {
+ // type Blah = impl Debug;
+ // let my_closure = || -> Blah { true };
+ // }
+ // ```
+ //
+ // requires us to explicitly process `foo()` in order
+ // to notice the defining usage of `Blah`.
+ Node::Item(it) => locator.visit_item(it),
+ Node::ImplItem(it) => locator.visit_impl_item(it),
+ Node::TraitItem(it) => locator.visit_trait_item(it),
+ other => bug!("{:?} is not a valid scope for an opaque type item", other),
+ }
+ }
+
+ let Some(hidden) = locator.found else {
+ 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) {
+ _ if scope == hir::CRATE_HIR_ID => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Mod(_), .. }) => "module",
+ Node::Item(hir::Item { kind: hir::ItemKind::Impl(_), .. }) => "impl",
+ _ => "item",
+ },
+ });
+ return tcx.ty_error(reported);
+ };
+
+ // Only check against typeck if we didn't already error
+ if !hidden.ty.references_error() {
+ for concrete_type in locator.typeck_types {
+ if concrete_type.ty != tcx.erase_regions(hidden.ty)
+ && !(concrete_type, hidden).references_error()
+ {
+ hidden.report_mismatch(&concrete_type, def_id, tcx).emit();
+ }
+ }
+ }
+
+ hidden.ty
+}
+
+struct TaitConstraintLocator<'tcx> {
+ tcx: TyCtxt<'tcx>,
+
+ /// def_id of the opaque type whose defining uses are being checked
+ def_id: LocalDefId,
+
+ /// as we walk the defining uses, we are checking that all of them
+ /// define the same hidden type. This variable is set to `Some`
+ /// with the first type that we find, and then later types are
+ /// checked against it (we also carry the span of that first
+ /// type).
+ found: Option<ty::OpaqueHiddenType<'tcx>>,
+
+ /// In the presence of dead code, typeck may figure out a hidden type
+ /// while borrowck will not. We collect these cases here and check at
+ /// the end that we actually found a type that matches (modulo regions).
+ typeck_types: Vec<ty::OpaqueHiddenType<'tcx>>,
+}
+
+impl TaitConstraintLocator<'_> {
+ #[instrument(skip(self), level = "debug")]
+ fn check(&mut self, item_def_id: LocalDefId) {
+ // Don't try to check items that cannot possibly constrain the type.
+ if !self.tcx.has_typeck_results(item_def_id) {
+ debug!("no constraint: no typeck results");
+ return;
+ }
+ // Calling `mir_borrowck` can lead to cycle errors through
+ // const-checking, avoid calling it if we don't have to.
+ // ```rust
+ // type Foo = impl Fn() -> usize; // when computing type for this
+ // const fn bar() -> Foo {
+ // || 0usize
+ // }
+ // const BAZR: Foo = bar(); // we would mir-borrowck this, causing cycles
+ // // because we again need to reveal `Foo` so we can check whether the
+ // // constant does not contain interior mutability.
+ // ```
+ let tables = self.tcx.typeck(item_def_id);
+ if let Some(guar) = tables.tainted_by_errors {
+ self.found = Some(ty::OpaqueHiddenType { span: DUMMY_SP, ty: self.tcx.ty_error(guar) });
+ return;
+ }
+ let Some(&typeck_hidden_ty) = tables.concrete_opaque_types.get(&self.def_id) else {
+ debug!("no constraints in typeck results");
+ return;
+ };
+ if self.typeck_types.iter().all(|prev| prev.ty != typeck_hidden_ty.ty) {
+ self.typeck_types.push(typeck_hidden_ty);
+ }
+
+ // Use borrowck to get the type with unerased regions.
+ let concrete_opaque_types = &self.tcx.mir_borrowck(item_def_id).concrete_opaque_types;
+ debug!(?concrete_opaque_types);
+ if let Some(&concrete_type) = concrete_opaque_types.get(&self.def_id) {
+ debug!(?concrete_type, "found constraint");
+ if let Some(prev) = &mut self.found {
+ if concrete_type.ty != prev.ty && !(concrete_type, prev.ty).references_error() {
+ let guar = prev.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
+ prev.ty = self.tcx.ty_error(guar);
+ }
+ } else {
+ self.found = Some(concrete_type);
+ }
+ }
+ }
+}
+
+impl<'tcx> intravisit::Visitor<'tcx> for TaitConstraintLocator<'tcx> {
+ type NestedFilter = nested_filter::All;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+ fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
+ trace!(?it.owner_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
+ intravisit::walk_item(self, it);
+ }
+ }
+ fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
+ trace!(?it.owner_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
+ intravisit::walk_impl_item(self, it);
+ }
+ }
+ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
+ intravisit::walk_trait_item(self, it);
+ }
+}
+
+pub(super) fn find_opaque_ty_constraints_for_rpit(
+ tcx: TyCtxt<'_>,
+ def_id: LocalDefId,
+ owner_def_id: LocalDefId,
+) -> Ty<'_> {
+ let concrete = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied();
+
+ if let Some(concrete) = concrete {
+ let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id);
+ debug!(?scope);
+ let mut locator = RpitConstraintChecker { def_id, tcx, found: concrete };
+
+ match tcx.hir().get(scope) {
+ Node::Item(it) => intravisit::walk_item(&mut locator, it),
+ Node::ImplItem(it) => intravisit::walk_impl_item(&mut locator, it),
+ Node::TraitItem(it) => intravisit::walk_trait_item(&mut locator, it),
+ other => bug!("{:?} is not a valid scope for an opaque type item", other),
+ }
+ }
+
+ concrete.map(|concrete| concrete.ty).unwrap_or_else(|| {
+ let table = tcx.typeck(owner_def_id);
+ if let Some(guar) = table.tainted_by_errors {
+ // Some error in the
+ // owner fn prevented us from populating
+ // the `concrete_opaque_types` table.
+ tcx.ty_error(guar)
+ } else {
+ table.concrete_opaque_types.get(&def_id).map(|ty| ty.ty).unwrap_or_else(|| {
+ // We failed to resolve the opaque type or it
+ // resolves to itself. We interpret this as the
+ // no values of the hidden type ever being constructed,
+ // so we can just make the hidden type be `!`.
+ // For backwards compatibility reasons, we fall back to
+ // `()` until we the diverging default is changed.
+ tcx.mk_diverging_default()
+ })
+ }
+ })
+}
+
+struct RpitConstraintChecker<'tcx> {
+ tcx: TyCtxt<'tcx>,
+
+ /// def_id of the opaque type whose defining uses are being checked
+ def_id: LocalDefId,
+
+ found: ty::OpaqueHiddenType<'tcx>,
+}
+
+impl RpitConstraintChecker<'_> {
+ #[instrument(skip(self), level = "debug")]
+ fn check(&self, def_id: LocalDefId) {
+ // Use borrowck to get the type with unerased regions.
+ let concrete_opaque_types = &self.tcx.mir_borrowck(def_id).concrete_opaque_types;
+ debug!(?concrete_opaque_types);
+ for (&def_id, &concrete_type) in concrete_opaque_types {
+ if def_id != self.def_id {
+ // Ignore constraints for other opaque types.
+ continue;
+ }
+
+ debug!(?concrete_type, "found constraint");
+
+ if concrete_type.ty != self.found.ty && !(concrete_type, self.found).references_error()
+ {
+ self.found.report_mismatch(&concrete_type, self.def_id, self.tcx).emit();
+ }
+ }
+ }
+}
+
+impl<'tcx> intravisit::Visitor<'tcx> for RpitConstraintChecker<'tcx> {
+ type NestedFilter = nested_filter::OnlyBodies;
+
+ fn nested_visit_map(&mut self) -> Self::Map {
+ self.tcx.hir()
+ }
+ fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) {
+ if let hir::ExprKind::Closure(closure) = ex.kind {
+ self.check(closure.def_id);
+ }
+ intravisit::walk_expr(self, ex);
+ }
+ fn visit_item(&mut self, it: &'tcx Item<'tcx>) {
+ trace!(?it.owner_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
+ intravisit::walk_item(self, it);
+ }
+ }
+ fn visit_impl_item(&mut self, it: &'tcx ImplItem<'tcx>) {
+ trace!(?it.owner_id);
+ // The opaque type itself or its children are not within its reveal scope.
+ if it.owner_id.def_id != self.def_id {
+ self.check(it.owner_id.def_id);
+ intravisit::walk_impl_item(self, it);
+ }
+ }
+ fn visit_trait_item(&mut self, it: &'tcx TraitItem<'tcx>) {
+ trace!(?it.owner_id);
+ self.check(it.owner_id.def_id);
+ intravisit::walk_trait_item(self, it);
+ }
+}
diff --git a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
index e18b0f082..9200c2aec 100644
--- a/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
+++ b/compiler/rustc_hir_analysis/src/constrained_generic_params.rs
@@ -59,7 +59,7 @@ struct ParameterCollector {
impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ParameterCollector {
fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<Self::BreakTy> {
match *t.kind() {
- ty::Alias(ty::Projection, ..) if !self.include_nonconstraining => {
+ ty::Alias(ty::Projection | ty::Inherent, ..) if !self.include_nonconstraining => {
// projections are not injective
return ControlFlow::Continue(());
}
diff --git a/compiler/rustc_hir_analysis/src/errors.rs b/compiler/rustc_hir_analysis/src/errors.rs
index 2a3a68348..6e7eb4f6c 100644
--- a/compiler/rustc_hir_analysis/src/errors.rs
+++ b/compiler/rustc_hir_analysis/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_errors::{
MultiSpan,
};
use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{self, print::TraitRefPrintOnlyTraitPath, Ty};
use rustc_span::{symbol::Ident, Span, Symbol};
#[derive(Diagnostic)]
@@ -108,6 +108,14 @@ pub struct CopyImplOnNonAdt {
}
#[derive(Diagnostic)]
+#[diag(hir_analysis_const_param_ty_impl_on_non_adt)]
+pub struct ConstParamTyImplOnNonAdt {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(hir_analysis_trait_object_declared_with_no_traits, code = "E0224")]
pub struct TraitObjectDeclaredWithNoTraits {
#[primary_span]
@@ -504,11 +512,23 @@ pub(crate) struct ReturnTypeNotationEqualityBound {
pub(crate) struct ReturnTypeNotationMissingMethod {
#[primary_span]
pub span: Span,
- pub trait_name: Symbol,
+ pub ty_name: String,
pub assoc_name: Symbol,
}
#[derive(Diagnostic)]
+#[diag(hir_analysis_return_type_notation_conflicting_bound)]
+#[note]
+pub(crate) struct ReturnTypeNotationConflictingBound<'tcx> {
+ #[primary_span]
+ pub span: Span,
+ pub ty_name: String,
+ pub assoc_name: Symbol,
+ pub first_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+ pub second_bound: ty::Binder<'tcx, TraitRefPrintOnlyTraitPath<'tcx>>,
+}
+
+#[derive(Diagnostic)]
#[diag(hir_analysis_placeholder_not_allowed_item_signatures, code = "E0121")]
pub(crate) struct PlaceholderNotAllowedItemSignatures {
#[primary_span]
@@ -631,3 +651,209 @@ pub(crate) struct SIMDFFIHighlyExperimental {
pub span: Span,
pub snip: String,
}
+
+#[derive(Diagnostic)]
+
+pub enum ImplNotMarkedDefault {
+ #[diag(hir_analysis_impl_not_marked_default, code = "E0520")]
+ #[note]
+ Ok {
+ #[primary_span]
+ #[label]
+ span: Span,
+ #[label(hir_analysis_ok_label)]
+ ok_label: Span,
+ ident: Symbol,
+ },
+ #[diag(hir_analysis_impl_not_marked_default_err, code = "E0520")]
+ #[note]
+ Err {
+ #[primary_span]
+ span: Span,
+ cname: Symbol,
+ ident: Symbol,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item, code = "E0046")]
+pub(crate) struct MissingTraitItem {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[subdiagnostic]
+ pub missing_trait_item_label: Vec<MissingTraitItemLabel>,
+ #[subdiagnostic]
+ pub missing_trait_item: Vec<MissingTraitItemSuggestion>,
+ #[subdiagnostic]
+ pub missing_trait_item_none: Vec<MissingTraitItemSuggestionNone>,
+ pub missing_items_msg: String,
+}
+
+#[derive(Subdiagnostic)]
+#[label(hir_analysis_missing_trait_item_label)]
+pub(crate) struct MissingTraitItemLabel {
+ #[primary_span]
+ pub span: Span,
+ pub item: Symbol,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+ hir_analysis_missing_trait_item_suggestion,
+ style = "tool-only",
+ applicability = "has-placeholders",
+ code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestion {
+ #[primary_span]
+ pub span: Span,
+ pub code: String,
+ pub snippet: String,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(
+ hir_analysis_missing_trait_item_suggestion,
+ style = "hidden",
+ applicability = "has-placeholders",
+ code = "{code}"
+)]
+pub(crate) struct MissingTraitItemSuggestionNone {
+ #[primary_span]
+ pub span: Span,
+ pub code: String,
+ pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_one_of_trait_item, code = "E0046")]
+pub(crate) struct MissingOneOfTraitItem {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note]
+ pub note: Option<Span>,
+ pub missing_items_msg: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_trait_item_unstable, code = "E0046")]
+#[note]
+pub(crate) struct MissingTraitItemUnstable {
+ #[primary_span]
+ pub span: Span,
+ #[note(hir_analysis_some_note)]
+ pub some_note: bool,
+ #[note(hir_analysis_none_note)]
+ pub none_note: bool,
+ pub missing_item_name: Symbol,
+ pub feature: Symbol,
+ pub reason: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_enum_variant, code = "E0731")]
+pub(crate) struct TransparentEnumVariant {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(hir_analysis_multi_label)]
+ pub spans: Vec<Span>,
+ #[label(hir_analysis_many_label)]
+ pub many: Option<Span>,
+ pub number: usize,
+ pub path: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized_enum, code = "E0690")]
+pub(crate) struct TransparentNonZeroSizedEnum<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(hir_analysis_labels)]
+ pub spans: Vec<Span>,
+ pub field_count: usize,
+ pub desc: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_transparent_non_zero_sized, code = "E0690")]
+pub(crate) struct TransparentNonZeroSized<'a> {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[label(hir_analysis_labels)]
+ pub spans: Vec<Span>,
+ pub field_count: usize,
+ pub desc: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_too_large_static)]
+pub(crate) struct TooLargeStatic {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_specialization_trait)]
+#[help]
+pub(crate) struct SpecializationTrait {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_closure_implicit_hrtb)]
+pub(crate) struct ClosureImplicitHrtb {
+ #[primary_span]
+ pub spans: Vec<Span>,
+ #[label]
+ pub for_sp: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_empty_specialization)]
+pub(crate) struct EmptySpecialization {
+ #[primary_span]
+ pub span: Span,
+ #[note]
+ pub base_impl_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_const_specialize)]
+pub(crate) struct ConstSpecialize {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_static_specialize)]
+pub(crate) struct StaticSpecialize {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_analysis_missing_tilde_const)]
+pub(crate) struct MissingTildeConst {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+pub(crate) enum DropImplPolarity {
+ #[diag(hir_analysis_drop_impl_negative)]
+ Negative {
+ #[primary_span]
+ span: Span,
+ },
+ #[diag(hir_analysis_drop_impl_reservation)]
+ Reservation {
+ #[primary_span]
+ span: Span,
+ },
+}
diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
index 8269a6dde..e4c6e6e39 100644
--- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs
@@ -4,7 +4,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{ForeignItem, ForeignItemKind};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{ObligationCause, WellFormedLoc};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Region, TyCtxt, TypeFoldable, TypeFolder};
use rustc_span::def_id::LocalDefId;
use rustc_trait_selection::traits::{self, ObligationCtxt};
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check.rs b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
index 82a96f8e6..612d4ff3d 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check.rs
@@ -15,7 +15,7 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_errors::struct_span_err;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::{Span, Symbol};
@@ -76,7 +76,7 @@ fn enforce_impl_params_are_constrained(tcx: TyCtxt<'_>, impl_def_id: LocalDefId)
// (#36836)
tcx.sess.delay_span_bug(
tcx.def_span(impl_def_id),
- &format!(
+ format!(
"potentially unconstrained type parameters weren't evaluated: {:?}",
impl_self_ty,
),
diff --git a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
index eb2fc3952..e84da2519 100644
--- a/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
+++ b/compiler/rustc_hir_analysis/src/impl_wf_check/min_specialization.rs
@@ -65,8 +65,8 @@
//! cause use after frees with purely safe code in the same way as specializing
//! on traits with methods can.
-use crate::constrained_generic_params as cgp;
use crate::errors::SubstsOnOverriddenImpl;
+use crate::{constrained_generic_params as cgp, errors};
use rustc_data_structures::fx::FxHashSet;
use rustc_hir as hir;
@@ -80,7 +80,7 @@ use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::Span;
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 rustc_trait_selection::traits::{self, translate_substs_with_cause, wf, ObligationCtxt};
pub(super) fn check_min_specialization(tcx: TyCtxt<'_>, impl_def_id: LocalDefId) {
if let Some(node) = parent_specialization_node(tcx, impl_def_id) {
@@ -100,12 +100,19 @@ fn parent_specialization_node(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId) -> Opti
// Implementing a normal trait isn't a specialization.
return None;
}
+ if trait_def.is_marker {
+ // Overlapping marker implementations are not really specializations.
+ return None;
+ }
Some(impl2_node)
}
/// 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) {
+ let span = tcx.def_span(impl1_def_id);
+ check_has_items(tcx, impl1_def_id, impl2_node, span);
+
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!(?impl2_def_id, ?impl2_substs);
@@ -116,7 +123,6 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
unconstrained_parent_impl_substs(tcx, impl2_def_id, impl2_substs)
};
- 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);
@@ -124,6 +130,13 @@ fn check_always_applicable(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node
}
}
+fn check_has_items(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node, span: Span) {
+ if let Node::Impl(impl2_id) = impl2_node && tcx.associated_item_def_ids(impl1_def_id).is_empty() {
+ let base_impl_span = tcx.def_span(impl2_id);
+ tcx.sess.emit_err(errors::EmptySpecialization { span, base_impl_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) {
@@ -137,9 +150,7 @@ fn check_constness(tcx: TyCtxt<'_>, impl1_def_id: LocalDefId, impl2_node: Node,
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();
+ tcx.sess.emit_err(errors::ConstSpecialize { span });
}
}
}
@@ -169,8 +180,21 @@ fn get_impl_substs(
ocx.assumed_wf_types(param_env, tcx.def_span(impl1_def_id), impl1_def_id);
let impl1_substs = InternalSubsts::identity_for_item(tcx, impl1_def_id);
- let impl2_substs =
- translate_substs(infcx, param_env, impl1_def_id.to_def_id(), impl1_substs, impl2_node);
+ let impl1_span = tcx.def_span(impl1_def_id);
+ let impl2_substs = translate_substs_with_cause(
+ infcx,
+ param_env,
+ impl1_def_id.to_def_id(),
+ impl1_substs,
+ impl2_node,
+ |_, span| {
+ traits::ObligationCause::new(
+ impl1_span,
+ impl1_def_id,
+ traits::ObligationCauseCode::BindingObligation(impl2_node.def_id(), span),
+ )
+ },
+ );
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@@ -274,7 +298,7 @@ fn check_duplicate_params<'tcx>(
if let (_, [duplicate, ..]) = base_params.partition_dedup() {
let param = impl1_substs[duplicate.0 as usize];
tcx.sess
- .struct_span_err(span, &format!("specializing impl repeats parameter `{}`", param))
+ .struct_span_err(span, format!("specializing impl repeats parameter `{}`", param))
.emit();
}
}
@@ -293,7 +317,7 @@ fn check_static_lifetimes<'tcx>(
span: Span,
) {
if tcx.any_free_region_meets(parent_substs, |r| r.is_static()) {
- tcx.sess.struct_span_err(span, "cannot specialize on `'static` lifetime").emit();
+ tcx.sess.emit_err(errors::StaticSpecialize { span });
}
}
@@ -368,7 +392,7 @@ fn check_predicates<'tcx>(
wf::obligations(infcx, tcx.param_env(impl1_def_id), impl1_def_id, 0, arg, span)
.unwrap();
- assert!(!obligations.needs_infer());
+ assert!(!obligations.has_infer());
impl2_predicates
.extend(traits::elaborate(tcx, obligations).map(|obligation| obligation.predicate))
}
@@ -438,7 +462,7 @@ fn trait_predicates_eq<'tcx>(
// 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();
+ tcx.sess.emit_err(errors::MissingTildeConst { span });
}
_ => {}
}
@@ -466,7 +490,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
tcx.sess
.struct_span_err(
span,
- &format!(
+ format!(
"cannot specialize on trait `{}`",
tcx.def_path_str(trait_ref.def_id),
),
@@ -481,7 +505,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
tcx.sess
.struct_span_err(
span,
- &format!("cannot specialize on associated type `{projection_ty} == {term}`",),
+ format!("cannot specialize on associated type `{projection_ty} == {term}`",),
)
.emit();
}
@@ -497,7 +521,7 @@ fn check_specialization_on<'tcx>(tcx: TyCtxt<'tcx>, predicate: ty::Predicate<'tc
}
_ => {
tcx.sess
- .struct_span_err(span, &format!("cannot specialize on predicate `{}`", predicate))
+ .struct_span_err(span, format!("cannot specialize on predicate `{}`", predicate))
.emit();
}
}
diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs
index 27e561803..5cd2cd50c 100644
--- a/compiler/rustc_hir_analysis/src/lib.rs
+++ b/compiler/rustc_hir_analysis/src/lib.rs
@@ -99,12 +99,12 @@ mod variance;
use rustc_errors::ErrorGuaranteed;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::Node;
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_macros::fluent_messages;
use rustc_middle::middle;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_middle::util;
use rustc_session::{config::EntryFnType, parse::feature_err};
@@ -116,7 +116,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode,
use std::ops::Not;
-use astconv::AstConv;
+use astconv::{AstConv, OnlySelfBounds};
use bounds::Bounds;
fluent_messages! { "../messages.ftl" }
@@ -496,8 +496,6 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorGuaranteed> {
tcx.hir().for_each_module(|module| tcx.ensure().check_mod_item_types(module))
});
- tcx.sess.time("item_bodies_checking", || tcx.typeck_item_bodies(()));
-
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);
@@ -530,9 +528,11 @@ pub fn hir_trait_to_predicates<'tcx>(
hir_trait,
DUMMY_SP,
ty::BoundConstness::NotConst,
+ ty::ImplPolarity::Positive,
self_ty,
&mut bounds,
true,
+ OnlySelfBounds(false),
);
bounds
diff --git a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
index d53c429ca..0cd2fc1aa 100644
--- a/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/implicit_infer.rs
@@ -210,6 +210,9 @@ fn insert_required_predicates_to_be_wf<'tcx>(
);
}
+ // FIXME(inherent_associated_types): Handle this case properly.
+ ty::Alias(ty::Inherent, _) => {}
+
_ => {}
}
}
diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs
index da72d2584..a8596c707 100644
--- a/compiler/rustc_hir_analysis/src/outlives/mod.rs
+++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs
@@ -1,7 +1,7 @@
use hir::Node;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, CratePredicatesMap, TyCtxt};
use rustc_span::symbol::sym;
@@ -61,7 +61,7 @@ fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clau
let span = tcx.def_span(item_def_id);
let mut err = tcx.sess.struct_span_err(span, "rustc_outlives");
- for p in &pred {
+ for p in pred {
err.note(p);
}
err.emit();
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
index 0bfbf99cb..c37dff61b 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/missing_cast_for_variadic_arg.rs
@@ -48,7 +48,7 @@ impl<'tcx> StructuredDiagnostic<'tcx> for MissingCastForVariadicArg<'tcx, '_> {
&self,
mut err: DiagnosticBuilder<'tcx, ErrorGuaranteed>,
) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
- err.note(&format!(
+ err.note(format!(
"certain types, like `{}`, must be casted before passing them to a \
variadic function, because of arcane ABI rules dictated by the C \
standard",
diff --git a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
index 8f4d81ec3..ee3457282 100644
--- a/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
+++ b/compiler/rustc_hir_analysis/src/structured_errors/wrong_number_of_generic_args.rs
@@ -395,7 +395,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
) -> String {
let fn_sig = self.tcx.hir().get_if_local(self.def_id).and_then(hir::Node::fn_sig);
let is_used_in_input = |def_id| {
- fn_sig.map_or(false, |fn_sig| {
+ fn_sig.is_some_and(|fn_sig| {
fn_sig.decl.inputs.iter().any(|ty| match ty.kind {
hir::TyKind::Path(hir::QPath::Resolved(
None,
@@ -480,7 +480,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let span = self.path_segment.ident.span;
let msg = self.create_error_message();
- self.tcx.sess.struct_span_err_with_code(span, &msg, self.code())
+ self.tcx.sess.struct_span_err_with_code(span, msg, self.code())
}
/// Builds the `expected 1 type argument / supplied 2 type arguments` message.
@@ -602,7 +602,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &msg,
+ msg,
sugg,
Applicability::HasPlaceholders,
);
@@ -625,7 +625,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders);
}
AngleBrackets::Implied => {
// We never encounter missing lifetimes in situations in which lifetimes are elided
@@ -652,7 +652,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
err.span_suggestion_verbose(
span.shrink_to_hi(),
- &msg,
+ msg,
sugg,
Applicability::HasPlaceholders,
);
@@ -683,7 +683,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
let sugg = format!("{}{}{}", sugg_prefix, suggested_args, sugg_suffix);
debug!("sugg: {:?}", sugg);
- err.span_suggestion_verbose(sugg_span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(sugg_span, msg, sugg, Applicability::HasPlaceholders);
}
}
}
@@ -885,7 +885,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
err.span_suggestion(
span_redundant_lt_args,
- &msg_lifetimes,
+ msg_lifetimes,
"",
Applicability::MaybeIncorrect,
);
@@ -927,7 +927,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
err.span_suggestion(
span_redundant_type_or_const_args,
- &msg_types_or_consts,
+ msg_types_or_consts,
"",
Applicability::MaybeIncorrect,
);
@@ -943,7 +943,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
if !suggestions.is_empty() {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"replace the generic bound{s} with the associated type{s}",
s = pluralize!(unbound_types.len())
),
@@ -969,7 +969,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
},
);
- err.span_suggestion(span, &msg, "", Applicability::MaybeIncorrect);
+ err.span_suggestion(span, msg, "", Applicability::MaybeIncorrect);
} else if redundant_lifetime_args && redundant_type_or_const_args {
remove_lifetime_args(err);
remove_type_or_const_args(err);
@@ -1029,7 +1029,7 @@ impl<'a, 'tcx> WrongNumberOfGenericArgs<'a, 'tcx> {
)
};
- err.span_note(spans, &msg);
+ err.span_note(spans, msg);
}
/// Add note if `impl Trait` is explicitly specified.
diff --git a/compiler/rustc_hir_analysis/src/variance/constraints.rs b/compiler/rustc_hir_analysis/src/variance/constraints.rs
index 408bec71e..6f0afae1b 100644
--- a/compiler/rustc_hir_analysis/src/variance/constraints.rs
+++ b/compiler/rustc_hir_analysis/src/variance/constraints.rs
@@ -92,7 +92,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> {
fn build_constraints_for_item(&mut self, def_id: LocalDefId) {
let tcx = self.tcx();
- debug!("build_constraints_for_item({})", tcx.def_path_str(def_id.to_def_id()));
+ debug!("build_constraints_for_item({})", tcx.def_path_str(def_id));
// Skip items with no generics - there's nothing to infer in them.
if tcx.generics_of(def_id).count() == 0 {
diff --git a/compiler/rustc_hir_analysis/src/variance/mod.rs b/compiler/rustc_hir_analysis/src/variance/mod.rs
index 0a45119ff..3ebd9e134 100644
--- a/compiler/rustc_hir_analysis/src/variance/mod.rs
+++ b/compiler/rustc_hir_analysis/src/variance/mod.rs
@@ -6,7 +6,7 @@
use rustc_arena::DroplessArena;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, CrateVariancesMap, SubstsRef, Ty, TyCtxt};
use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable};
use std::ops::ControlFlow;
@@ -105,7 +105,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
if let ty::RegionKind::ReEarlyBound(ebr) = r.kind() {
self.variances[ebr.index as usize] = ty::Invariant;
}
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
#[instrument(level = "trace", skip(self), ret)]
@@ -153,8 +153,7 @@ fn variance_of_opaque(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[ty::Varianc
let mut collector =
OpaqueTypeLifetimeCollector { tcx, root_def_id: item_def_id.to_def_id(), variances };
let id_substs = ty::InternalSubsts::identity_for_item(tcx, item_def_id);
- for pred in tcx.bound_explicit_item_bounds(item_def_id.to_def_id()).transpose_iter() {
- let pred = pred.map_bound(|(pred, _)| *pred).subst(tcx, id_substs);
+ for (pred, _) in tcx.explicit_item_bounds(item_def_id).subst_iter_copied(tcx, id_substs) {
debug!(?pred);
// We only ignore opaque type substs if the opaque type is the outermost type.
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index 74f5b3590..d93e8efc1 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1407,10 +1407,16 @@ impl<'a> State<'a> {
self.print_type(ty);
}
hir::ExprKind::Type(expr, ty) => {
- let prec = AssocOp::Colon.precedence() as i8;
- self.print_expr_maybe_paren(expr, prec);
- self.word_space(":");
+ self.word("type_ascribe!(");
+ self.ibox(0);
+ self.print_expr(expr);
+
+ self.word(",");
+ self.space_if_not_bol();
self.print_type(ty);
+
+ self.end();
+ self.word(")");
}
hir::ExprKind::DropTemps(init) => {
// Print `{`:
@@ -1551,6 +1557,23 @@ impl<'a> State<'a> {
self.word("asm!");
self.print_inline_asm(asm);
}
+ hir::ExprKind::OffsetOf(container, ref fields) => {
+ self.word("offset_of!(");
+ self.print_type(container);
+ self.word(",");
+ self.space();
+
+ if let Some((&first, rest)) = fields.split_first() {
+ self.print_ident(first);
+
+ for &field in rest {
+ self.word(".");
+ self.print_ident(field);
+ }
+ }
+
+ self.word(")");
+ }
hir::ExprKind::Yield(expr, _) => {
self.word_space("yield");
self.print_expr_maybe_paren(expr, parser::PREC_JUMP);
diff --git a/compiler/rustc_hir_typeck/Cargo.toml b/compiler/rustc_hir_typeck/Cargo.toml
index 093f9bb84..13e1ea31c 100644
--- a/compiler/rustc_hir_typeck/Cargo.toml
+++ b/compiler/rustc_hir_typeck/Cargo.toml
@@ -12,6 +12,7 @@ rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_graphviz = { path = "../rustc_graphviz" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_hir = { path = "../rustc_hir" }
diff --git a/compiler/rustc_hir_typeck/messages.ftl b/compiler/rustc_hir_typeck/messages.ftl
index 2c537bf40..aab432eee 100644
--- a/compiler/rustc_hir_typeck/messages.ftl
+++ b/compiler/rustc_hir_typeck/messages.ftl
@@ -1,79 +1,94 @@
-hir_typeck_field_multiply_specified_in_initializer =
- field `{$ident}` specified more than once
- .label = used more than once
- .previous_use_label = first use of `{$ident}`
-
-hir_typeck_copy_impl_on_type_with_dtor =
- the trait `Copy` cannot be implemented for this type; the type has a destructor
- .label = `Copy` not allowed on types with destructors
-
-hir_typeck_multiple_relaxed_default_bounds =
- type parameter has more than one relaxed default bound, only one is supported
-
-hir_typeck_copy_impl_on_non_adt =
- the trait `Copy` cannot be implemented for this type
- .label = type is not a structure or enumeration
+hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
-hir_typeck_trait_object_declared_with_no_traits =
- at least one trait is required for an object type
- .alias_span = this alias does not contain a trait
+hir_typeck_add_return_type_add = try adding a return type
-hir_typeck_functional_record_update_on_non_struct =
- functional record update syntax requires a struct
+hir_typeck_add_return_type_missing_here = a return type might be missing here
-hir_typeck_return_stmt_outside_of_fn_body =
- return statement outside of function body
- .encl_body_label = the return is part of this body...
- .encl_fn_label = ...not the enclosing function body
+hir_typeck_address_of_temporary_taken = cannot take address of a temporary
+ .label = temporary value
-hir_typeck_yield_expr_outside_of_generator =
- yield expression outside of generator literal
+hir_typeck_arg_mismatch_indeterminate = argument type mismatch was detected, but rustc had trouble determining where
+ .note = we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new
-hir_typeck_struct_expr_non_exhaustive =
- cannot create non-exhaustive {$what} using struct expression
+hir_typeck_candidate_trait_note = `{$trait_name}` defines an item `{$item_name}`{$action_or_ty ->
+ [NONE] {""}
+ [implement] , perhaps you need to implement it
+ *[other] , perhaps you need to restrict type parameter `{$action_or_ty}` with it
+}
-hir_typeck_method_call_on_unknown_type =
- the type of this value must be known to call a method on a raw pointer on it
+hir_typeck_const_select_must_be_const = this argument must be a `const fn`
+ .help = consult the documentation on `const_eval_select` for more information
-hir_typeck_address_of_temporary_taken = cannot take address of a temporary
- .label = temporary value
+hir_typeck_const_select_must_be_fn = this argument must be a function item
+ .note = expected a function item, found {$ty}
+ .help = consult the documentation on `const_eval_select` for more information
-hir_typeck_add_return_type_add = try adding a return type
+hir_typeck_convert_to_str = try converting the passed type into a `&str`
-hir_typeck_add_return_type_missing_here = a return type might be missing here
+hir_typeck_ctor_is_private = tuple struct constructor `{$def}` is private
hir_typeck_expected_default_return_type = expected `()` because of default return type
hir_typeck_expected_return_type = expected `{$expected}` because of return type
-hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+hir_typeck_field_multiply_specified_in_initializer =
+ field `{$ident}` specified more than once
+ .label = used more than once
+ .previous_use_label = first use of `{$ident}`
-hir_typeck_add_missing_parentheses_in_range = you must surround the range in parentheses to call its `{$func_name}` function
+hir_typeck_fru_expr = this expression does not end in a comma...
+hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
+hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
+hir_typeck_fru_suggestion =
+ to set the remaining fields{$expr ->
+ [NONE]{""}
+ *[other] {" "}from `{$expr}`
+ }, separate the last named field with a comma
-hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
-hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
+hir_typeck_functional_record_update_on_non_struct =
+ functional record update syntax requires a struct
+hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
hir_typeck_lang_start_expected_sig_note = the `start` lang item should have the signature `fn(fn() -> T, isize, *const *const u8, u8) -> isize`
+hir_typeck_lang_start_incorrect_number_params = incorrect number of parameters for the `start` lang item
+hir_typeck_lang_start_incorrect_number_params_note_expected_count = the `start` lang item should have four parameters, but found {$found_param_count}
+
hir_typeck_lang_start_incorrect_param = parameter {$param_num} of the `start` lang item is incorrect
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
hir_typeck_lang_start_incorrect_ret_ty = the return type of the `start` lang item is incorrect
.suggestion = change the type from `{$found_ty}` to `{$expected_ty}`
-hir_typeck_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
-hir_typeck_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+hir_typeck_method_call_on_unknown_raw_pointee =
+ cannot call a method on a raw pointer with an unknown pointee type
-hir_typeck_convert_to_str = try converting the passed type into a `&str`
+hir_typeck_missing_parentheses_in_range = can't call method `{$method_name}` on type `{$ty_str}`
+
+hir_typeck_no_associated_item = no {$item_kind} named `{$item_name}` found for {$ty_prefix} `{$ty_str}`{$trait_missing_method ->
+ [true] {""}
+ *[other] {" "}in the current scope
+}
+
+hir_typeck_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
hir_typeck_op_trait_generic_params = `{$method_name}` must not have any generic parameters
-hir_typeck_fru_note = this expression may have been misinterpreted as a `..` range expression
-hir_typeck_fru_expr = this expression does not end in a comma...
-hir_typeck_fru_expr2 = ... so this is interpreted as a `..` range expression, instead of functional record update syntax
-hir_typeck_fru_suggestion =
- to set the remaining fields{$expr ->
- [NONE]{""}
- *[other] {" "}from `{$expr}`
- }, separate the last named field with a comma
+hir_typeck_return_stmt_outside_of_fn_body =
+ return statement outside of function body
+ .encl_body_label = the return is part of this body...
+ .encl_fn_label = ...not the enclosing function body
+
+hir_typeck_struct_expr_non_exhaustive =
+ cannot create non-exhaustive {$what} using struct expression
+
+hir_typeck_suggest_boxing_note = for more on the distinction between the stack and the heap, read https://doc.rust-lang.org/book/ch15-01-box.html, https://doc.rust-lang.org/rust-by-example/std/box.html, and https://doc.rust-lang.org/std/boxed/index.html
+
+hir_typeck_suggest_boxing_when_appropriate = store this in the heap by calling `Box::new`
+
+hir_typeck_union_pat_dotdot = `..` cannot be used in union patterns
+
+hir_typeck_union_pat_multiple_fields = union patterns should have exactly one field
+hir_typeck_yield_expr_outside_of_generator =
+ yield expression outside of generator literal
diff --git a/compiler/rustc_hir_typeck/src/_match.rs b/compiler/rustc_hir_typeck/src/_match.rs
index 6c2ce6272..7d2f7e876 100644
--- a/compiler/rustc_hir_typeck/src/_match.rs
+++ b/compiler/rustc_hir_typeck/src/_match.rs
@@ -271,7 +271,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&cause,
&mut |err| {
if let Some((span, msg)) = &ret_reason {
- err.span_label(*span, msg);
+ err.span_label(*span, msg.clone());
} else if let ExprKind::Block(block, _) = &then_expr.kind
&& let Some(expr) = &block.expr
{
@@ -530,7 +530,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for ty in [first_ty, second_ty] {
for (pred, _) in self
.tcx
- .bound_explicit_item_bounds(rpit_def_id)
+ .explicit_item_bounds(rpit_def_id)
.subst_iter_copied(self.tcx, substs)
{
let pred = pred.kind().rebind(match pred.kind().skip_binder() {
diff --git a/compiler/rustc_hir_typeck/src/callee.rs b/compiler/rustc_hir_typeck/src/callee.rs
index 5235710a2..655ab94eb 100644
--- a/compiler/rustc_hir_typeck/src/callee.rs
+++ b/compiler/rustc_hir_typeck/src/callee.rs
@@ -397,7 +397,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.sess
.struct_span_err(
callee_expr.span,
- &format!("evaluate({:?}) = {:?}", predicate, result),
+ format!("evaluate({:?}) = {:?}", predicate, result),
)
.span_label(predicate_span, "predicate")
.emit();
@@ -630,7 +630,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Some((removal_span, kind, path)) = &unit_variant {
err.span_suggestion_verbose(
*removal_span,
- &format!(
+ format!(
"`{path}` is a unit {kind}, and does not take parentheses to be constructed",
),
"",
diff --git a/compiler/rustc_hir_typeck/src/cast.rs b/compiler/rustc_hir_typeck/src/cast.rs
index 1481c038c..98c683f02 100644
--- a/compiler/rustc_hir_typeck/src/cast.rs
+++ b/compiler/rustc_hir_typeck/src/cast.rs
@@ -146,7 +146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let reported = self
.tcx
.sess
- .delay_span_bug(span, &format!("`{:?}` should be sized but is not?", t));
+ .delay_span_bug(span, format!("`{:?}` should be sized but is not?", t));
return Err(reported);
}
})
@@ -270,7 +270,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
fcx,
);
if self.cast_ty.is_integral() {
- err.help(&format!(
+ err.help(format!(
"cast through {} first",
match e {
CastError::NeedViaPtr => "a raw pointer",
@@ -292,7 +292,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
self.cast_ty,
fcx,
)
- .help(&format!(
+ .help(format!(
"cast through {} first",
match e {
CastError::NeedViaInt => "an integer",
@@ -465,7 +465,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
.sess
.source_map()
.span_to_snippet(self.expr_span)
- .map_or(false, |snip| snip.starts_with('('));
+ .is_ok_and(|snip| snip.starts_with('('));
// Very crude check to see whether the expression must be wrapped
// in parentheses for the suggestion to work (issue #89497).
@@ -651,13 +651,13 @@ impl<'a, 'tcx> CastCheck<'tcx> {
);
}
Err(_) => {
- let msg = &format!("did you mean `&{}{}`?", mtstr, tstr);
+ let msg = format!("did you mean `&{}{}`?", mtstr, tstr);
err.span_help(self.cast_span, msg);
}
}
} else {
let msg =
- &format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
+ format!("consider using an implicit coercion to `&{mtstr}{tstr}` instead");
err.span_help(self.span, msg);
}
}
@@ -674,7 +674,7 @@ impl<'a, 'tcx> CastCheck<'tcx> {
Err(_) => {
err.span_help(
self.cast_span,
- &format!("you might have meant `Box<{tstr}>`"),
+ format!("you might have meant `Box<{tstr}>`"),
);
}
}
diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs
index bf8259ff7..bfabd44bb 100644
--- a/compiler/rustc_hir_typeck/src/check.rs
+++ b/compiler/rustc_hir_typeck/src/check.rs
@@ -32,6 +32,7 @@ pub(super) fn check_fn<'a, 'tcx>(
fn_def_id: LocalDefId,
body: &'tcx hir::Body<'tcx>,
can_be_generator: Option<hir::Movability>,
+ params_can_be_unsized: bool,
) -> Option<GeneratorTypes<'tcx>> {
let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id);
@@ -94,7 +95,7 @@ pub(super) fn check_fn<'a, 'tcx>(
// The check for a non-trivial pattern is a hack to avoid duplicate warnings
// for simple cases like `fn foo(x: Trait)`,
// where we would error once on the parameter as a whole, and once on the binding `x`.
- if param.pat.simple_ident().is_none() && !tcx.features().unsized_fn_params {
+ if param.pat.simple_ident().is_none() && !params_can_be_unsized {
fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span));
}
@@ -103,24 +104,8 @@ pub(super) fn check_fn<'a, 'tcx>(
fcx.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig);
- if let ty::Dynamic(_, _, ty::Dyn) = 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
- // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this
- // causes unsized errors caused by the `declared_ret_ty` to point at the return expression,
- // while keeping the current ordering we will ignore the tail expression's type because we
- // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr`
- // because we will trigger "unreachable expression" lints unconditionally.
- // Because of all of this, we perform a crude check to know whether the simplest `!Sized`
- // case that a newcomer might make, returning a bare trait, and in that case we populate
- // the tail expression's type so that the suggestion will be correct, but ignore all other
- // possible cases.
- fcx.check_expr(&body.value);
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- } else {
- fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
- fcx.check_return_expr(&body.value, false);
- }
+ fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType);
+ fcx.check_return_expr(&body.value, 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.
diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs
index 8c2495e1d..9659a0ec1 100644
--- a/compiler/rustc_hir_typeck/src/closure.rs
+++ b/compiler/rustc_hir_typeck/src/closure.rs
@@ -89,6 +89,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expr_def_id,
body,
closure.movability,
+ // Closure "rust-call" ABI doesn't support unsized params
+ false,
);
let parent_substs = InternalSubsts::identity_for_item(
@@ -172,7 +174,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.deduce_closure_signature_from_predicates(
expected_ty,
- self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
+ self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs),
),
ty::Dynamic(ref object_type, ..) => {
let sig = object_type.projection_bounds().find_map(|pb| {
@@ -713,13 +715,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => self
.tcx
- .bound_explicit_item_bounds(def_id)
+ .explicit_item_bounds(def_id)
.subst_iter_copied(self.tcx, substs)
.find_map(|(p, s)| get_future_output(p, s))?,
ty::Error(_) => return None,
ty::Alias(ty::Projection, proj) if self.tcx.is_impl_trait_in_trait(proj.def_id) => self
.tcx
- .bound_explicit_item_bounds(proj.def_id)
+ .explicit_item_bounds(proj.def_id)
.subst_iter_copied(self.tcx, proj.substs)
.find_map(|(p, s)| get_future_output(p, s))?,
_ => span_bug!(
diff --git a/compiler/rustc_hir_typeck/src/coercion.rs b/compiler/rustc_hir_typeck/src/coercion.rs
index 8fa3bcd68..08c4082e8 100644
--- a/compiler/rustc_hir_typeck/src/coercion.rs
+++ b/compiler/rustc_hir_typeck/src/coercion.rs
@@ -601,7 +601,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.tcx,
cause,
self.fcx.param_env,
- self.tcx.mk_trait_ref(coerce_unsized_did, [coerce_source, coerce_target])
+ ty::TraitRef::new(self.tcx, coerce_unsized_did, [coerce_source, coerce_target])
)];
let mut has_unsized_tuple_coercion = false;
@@ -707,9 +707,9 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
&self.tcx.sess.parse_sess,
sym::trait_upcasting,
self.cause.span,
- &format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
+ format!("cannot cast `{sub}` to `{sup}`, trait upcasting coercion is experimental"),
);
- err.note(&format!("required when coercing `{source}` into `{target}`"));
+ err.note(format!("required when coercing `{source}` into `{target}`"));
err.emit();
}
@@ -764,8 +764,11 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
self.tcx,
self.cause.clone(),
self.param_env,
- ty::Binder::dummy(
- self.tcx.at(self.cause.span).mk_trait_ref(hir::LangItem::PointerLike, [a]),
+ ty::TraitRef::from_lang_item(
+ self.tcx,
+ hir::LangItem::PointerLike,
+ self.cause.span,
+ [a],
),
));
@@ -976,7 +979,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Attempt to coerce an expression to a type, and return the
/// adjusted type of the expression, if successful.
/// Adjustments are only recorded if the coercion succeeded.
- /// The expressions *must not* have any pre-existing adjustments.
+ /// The expressions *must not* have any preexisting adjustments.
pub fn try_coerce(
&self,
expr: &hir::Expr<'_>,
@@ -1340,7 +1343,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
}
/// As an optimization, you can create a `CoerceMany` with a
- /// pre-existing slice of expressions. In this case, you are
+ /// preexisting slice of expressions. In this case, you are
/// expected to pass each element in the slice to `coerce(...)` in
/// order. This is used with arrays in particular to avoid
/// needlessly cloning the slice.
@@ -1657,7 +1660,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
"the function expects a value to always be returned, but loops might run zero times",
);
if MAXITER < ret_exprs.len() {
- err.note(&format!(
+ err.note(format!(
"if the loop doesn't execute, {} other values would never get returned",
ret_exprs.len() - MAXITER
));
@@ -1767,7 +1770,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
{
err.span_note(
sp,
- &format!(
+ format!(
"return type inferred to be `{}` here",
expected
),
@@ -1811,7 +1814,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
.span_to_snippet(return_sp)
.unwrap_or_else(|_| "dyn Trait".to_string());
let mut snippet_iter = snippet.split_whitespace();
- let has_impl = snippet_iter.next().map_or(false, |s| s == "impl");
+ let has_impl = snippet_iter.next().is_some_and(|s| s == "impl");
// Only suggest `Box<dyn Trait>` if `Trait` in `impl Trait` is object safe.
let mut is_object_safe = false;
if let hir::FnRetTy::Return(ty) = fn_output
@@ -1831,7 +1834,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
bound
.trait_ref()
.and_then(|t| t.trait_def_id())
- .map_or(false, |def_id| {
+ .is_some_and(|def_id| {
fcx.tcx.check_is_object_safe(def_id)
})
})
@@ -1864,7 +1867,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> {
Applicability::MaybeIncorrect,
);
} else {
- err.help(&format!(
+ err.help(format!(
"if the trait `{}` were object safe, you could return a boxed trait object",
&snippet[5..]
));
diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs
index 13442c316..b50630e63 100644
--- a/compiler/rustc_hir_typeck/src/demand.rs
+++ b/compiler/rustc_hir_typeck/src/demand.rs
@@ -17,7 +17,6 @@ use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, Article, AssocItem, Ty, TypeAndMut, TypeFoldable};
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{BytePos, Span, DUMMY_SP};
-use rustc_target::abi::FieldIdx;
use rustc_trait_selection::infer::InferCtxtExt as _;
use rustc_trait_selection::traits::ObligationCause;
@@ -52,7 +51,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
|| self.suggest_non_zero_new_unwrap(err, expr, expected, expr_ty)
|| self.suggest_calling_boxed_future_when_appropriate(err, expr, expected, expr_ty)
|| self.suggest_no_capture_closure(err, expected, expr_ty)
- || self.suggest_boxing_when_appropriate(err, expr, expected, expr_ty)
+ || self.suggest_boxing_when_appropriate(err, expr.span, expr.hir_id, 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_clone_for_ref(err, expr, expr_ty, expected)
@@ -87,9 +86,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.emit_type_mismatch_suggestions(err, expr, expr_ty, expected, expected_ty_expr, error);
self.note_type_is_not_clone(err, expected, expr_ty, expr);
self.note_internal_mutation_in_method(err, expr, Some(expected), expr_ty);
- self.check_for_range_as_method_call(err, expr, expr_ty, expected);
- self.check_for_binding_assigned_block_without_tail_expression(err, expr, expr_ty, expected);
- self.check_wrong_return_type_due_to_generic_arg(err, expr, expr_ty);
+ self.suggest_method_call_on_range_literal(err, expr, expr_ty, expected);
+ self.suggest_return_binding_for_missing_tail_expr(err, expr, expr_ty, expected);
+ self.note_wrong_return_ty_due_to_generic_arg(err, expr, expr_ty);
}
/// Requires that the two types unify, and prints an error message if
@@ -544,13 +543,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We are pointing at the binding's type or initializer value, but it's pattern
// is in a different line, so we point at both.
err.span_label(secondary_span, "expected due to the type of this binding");
- err.span_label(primary_span, &format!("expected due to this{post_message}"));
+ err.span_label(primary_span, format!("expected due to this{post_message}"));
} else if post_message == "" {
// We are pointing at either the assignment lhs or the binding def pattern.
err.span_label(primary_span, "expected due to the type of this binding");
} else {
// We are pointing at the binding's type or initializer value.
- err.span_label(primary_span, &format!("expected due to this{post_message}"));
+ err.span_label(primary_span, format!("expected due to this{post_message}"));
}
if !lhs.is_syntactic_place_expr() {
@@ -567,7 +566,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) if rhs.hir_id == expr.hir_id
&& self.typeck_results.borrow().expr_ty_adjusted_opt(lhs) == Some(expected) =>
{
- err.span_label(lhs.span, &format!("expected because this is `{expected}`"));
+ err.span_label(lhs.span, format!("expected because this is `{expected}`"));
}
_ => {}
}
@@ -705,19 +704,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
});
err.span_note(
path_span,
- &format!(
+ format!(
"the `{}` call is resolved to the method in `{container}`, shadowing {tail}",
path.ident,
),
);
if suggestions.len() > other_methods_in_scope.len() {
- err.note(&format!(
+ err.note(format!(
"additionally, there are {} other available methods that aren't in scope",
suggestions.len() - other_methods_in_scope.len()
));
}
err.multipart_suggestions(
- &format!(
+ format!(
"you might have meant to call {}; you can use the fully-qualified path to call {} \
explicitly",
if suggestions.len() == 1 {
@@ -875,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
variant.fields.len() == 1
})
.filter_map(|variant| {
- let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+ let sole_field = &variant.single_field();
let field_is_local = sole_field.did.is_local();
let field_is_accessible =
@@ -942,7 +941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
[(variant, ctor_kind, field_name, note)] => {
// Just a single matching variant.
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"try wrapping the expression in `{variant}`{note}",
note = note.as_deref().unwrap_or("")
),
@@ -954,7 +953,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
// More than one matching variant.
err.multipart_suggestions(
- &format!(
+ format!(
"try wrapping the expression in a variant of `{}`",
self.tcx.def_path_str(expected_adt.did())
),
@@ -1088,7 +1087,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// ```ignore (illustrative)
/// opt.map(|param| { takes_ref(param) });
/// ```
- fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Span, &'static str, String)> {
+ fn can_use_as_ref(&self, expr: &hir::Expr<'_>) -> Option<(Vec<(Span, String)>, &'static str)> {
let hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) = expr.kind else {
return None;
};
@@ -1134,12 +1133,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
_ => false,
};
- match (is_as_ref_able, self.sess().source_map().span_to_snippet(method_path.ident.span)) {
- (true, Ok(src)) => {
- let suggestion = format!("as_ref().{}", src);
- Some((method_path.ident.span, "consider using `as_ref` instead", suggestion))
- }
- _ => None,
+ if is_as_ref_able {
+ Some((
+ vec![(method_path.ident.span.shrink_to_lo(), "as_ref().".to_string())],
+ "consider using `as_ref` instead",
+ ))
+ } else {
+ None
}
}
@@ -1218,14 +1218,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// In addition of this check, it also checks between references mutability state. If the
/// expected is mutable but the provided isn't, maybe we could just say "Hey, try with
/// `&mut`!".
- pub fn check_ref(
+ pub fn suggest_deref_or_ref(
&self,
expr: &hir::Expr<'tcx>,
checked_ty: Ty<'tcx>,
expected: Ty<'tcx>,
) -> Option<(
- Span,
- String,
+ Vec<(Span, String)>,
String,
Applicability,
bool, /* verbose */
@@ -1255,30 +1254,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& let Ok(src) = sm.span_to_snippet(sp)
&& replace_prefix(&src, "b\"", "\"").is_some()
{
- let pos = sp.lo() + BytePos(1);
- return Some((
- sp.with_hi(pos),
- "consider removing the leading `b`".to_string(),
- String::new(),
- Applicability::MachineApplicable,
- true,
- false,
- ));
- }
- }
+ let pos = sp.lo() + BytePos(1);
+ return Some((
+ vec![(sp.with_hi(pos), String::new())],
+ "consider removing the leading `b`".to_string(),
+ Applicability::MachineApplicable,
+ true,
+ false,
+ ));
+ }
+ }
(&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => {
if let hir::ExprKind::Lit(_) = expr.kind
&& let Ok(src) = sm.span_to_snippet(sp)
&& replace_prefix(&src, "\"", "b\"").is_some()
{
- return Some((
- sp.shrink_to_lo(),
- "consider adding a leading `b`".to_string(),
- "b".to_string(),
- Applicability::MachineApplicable,
- true,
- false,
- ));
+ return Some((
+ vec![(sp.shrink_to_lo(), "b".to_string())],
+ "consider adding a leading `b`".to_string(),
+ Applicability::MachineApplicable,
+ true,
+ false,
+ ));
}
}
_ => {}
@@ -1321,66 +1318,73 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner) = expr.kind
- && let Some(1) = self.deref_steps(expected, checked_ty) {
+ && let Some(1) = self.deref_steps(expected, checked_ty)
+ {
// We have `*&T`, check if what was expected was `&T`.
// If so, we may want to suggest removing a `*`.
sugg_sp = sugg_sp.with_hi(inner.span.lo());
return Some((
- sugg_sp,
+ vec![(sugg_sp, String::new())],
"consider removing deref here".to_string(),
- "".to_string(),
Applicability::MachineApplicable,
true,
false,
));
}
- if let Ok(src) = sm.span_to_snippet(sugg_sp) {
- let needs_parens = match expr.kind {
- // parenthesize if needed (Issue #46756)
- hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
- // parenthesize borrows of range literals (Issue #54505)
- _ if is_range_literal(expr) => true,
- _ => false,
- };
-
- if let Some(sugg) = self.can_use_as_ref(expr) {
- return Some((
- sugg.0,
- sugg.1.to_string(),
- sugg.2,
- Applicability::MachineApplicable,
- false,
- false,
- ));
- }
-
- let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
- Some(ident) => format!("{ident}: "),
- None => String::new(),
- };
-
- if let Some(hir::Node::Expr(hir::Expr {
- kind: hir::ExprKind::Assign(..),
- ..
- })) = self.tcx.hir().find_parent(expr.hir_id)
- {
- if mutability.is_mut() {
- // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
- return None;
- }
- }
+ let needs_parens = match expr.kind {
+ // parenthesize if needed (Issue #46756)
+ hir::ExprKind::Cast(_, _) | hir::ExprKind::Binary(_, _, _) => true,
+ // parenthesize borrows of range literals (Issue #54505)
+ _ if is_range_literal(expr) => true,
+ _ => false,
+ };
- let sugg_expr = if needs_parens { format!("({src})") } else { src };
+ if let Some((sugg, msg)) = self.can_use_as_ref(expr) {
return Some((
- sp,
- format!("consider {}borrowing here", mutability.mutably_str()),
- format!("{prefix}{}{sugg_expr}", mutability.ref_prefix_str()),
+ sugg,
+ msg.to_string(),
Applicability::MachineApplicable,
- false,
+ true,
false,
));
}
+
+ let prefix = match self.maybe_get_struct_pattern_shorthand_field(expr) {
+ Some(ident) => format!("{ident}: "),
+ None => String::new(),
+ };
+
+ if let Some(hir::Node::Expr(hir::Expr {
+ kind: hir::ExprKind::Assign(..),
+ ..
+ })) = self.tcx.hir().find_parent(expr.hir_id)
+ {
+ if mutability.is_mut() {
+ // Suppressing this diagnostic, we'll properly print it in `check_expr_assign`
+ return None;
+ }
+ }
+
+ let sugg = mutability.ref_prefix_str();
+ let (sugg, verbose) = if needs_parens {
+ (
+ vec![
+ (sp.shrink_to_lo(), format!("{prefix}{sugg}(")),
+ (sp.shrink_to_hi(), ")".to_string()),
+ ],
+ false,
+ )
+ } else {
+ (vec![(sp.shrink_to_lo(), format!("{prefix}{sugg}"))], true)
+ };
+ return Some((
+ sugg,
+ format!("consider {}borrowing here", mutability.mutably_str()),
+ Applicability::MachineApplicable,
+ verbose,
+ false,
+ ));
}
}
(
@@ -1402,23 +1406,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& sm.is_span_accessible(call_span)
{
return Some((
- sp.with_hi(call_span.lo()),
+ vec![(sp.with_hi(call_span.lo()), String::new())],
"consider removing the borrow".to_string(),
- String::new(),
Applicability::MachineApplicable,
true,
- true
+ true,
));
}
return None;
}
- if sp.contains(expr.span)
- && sm.is_span_accessible(expr.span)
- {
+ if sp.contains(expr.span) && sm.is_span_accessible(expr.span) {
return Some((
- sp.with_hi(expr.span.lo()),
+ vec![(sp.with_hi(expr.span.lo()), String::new())],
"consider removing the borrow".to_string(),
- String::new(),
Applicability::MachineApplicable,
true,
true,
@@ -1442,23 +1442,30 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let suggestion = replace_prefix(&src, old_prefix, &new_prefix).map(|_| {
// skip `&` or `&mut ` if both mutabilities are mutable
- let lo = sp.lo() + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
+ let lo = sp.lo()
+ + BytePos(min(old_prefix.len(), mutbl_b.ref_prefix_str().len()) as _);
// skip `&` or `&mut `
let hi = sp.lo() + BytePos(old_prefix.len() as _);
let sp = sp.with_lo(lo).with_hi(hi);
(
sp,
- format!("{}{derefs}", if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }),
- if mutbl_b <= mutbl_a { Applicability::MachineApplicable } else { Applicability::MaybeIncorrect }
+ format!(
+ "{}{derefs}",
+ if mutbl_a != mutbl_b { mutbl_b.prefix_str() } else { "" }
+ ),
+ if mutbl_b <= mutbl_a {
+ Applicability::MachineApplicable
+ } else {
+ Applicability::MaybeIncorrect
+ },
)
});
if let Some((span, src, applicability)) = suggestion {
return Some((
- span,
+ vec![(span, src)],
"consider dereferencing".to_string(),
- src,
applicability,
true,
false,
@@ -1487,9 +1494,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If we've reached our target type with just removing `&`, then just print now.
if steps == 0 && !remove.trim().is_empty() {
return Some((
- prefix_span,
+ vec![(prefix_span, String::new())],
format!("consider removing the `{}`", remove.trim()),
- String::new(),
// Do not remove `&&` to get to bool, because it might be something like
// { a } && b, which we have a separate fixup suggestion that is more
// likely correct...
@@ -1509,6 +1515,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// FIXME(compiler-errors): We can actually do this if the checked_ty is
// `steps` layers of boxes, not just one, but this is easier and most likely.
|| (checked_ty.is_box() && steps == 1)
+ // We can always deref a binop that takes its arguments by ref.
+ || matches!(
+ self.tcx.hir().get_parent(expr.hir_id),
+ hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Binary(op, ..), .. })
+ if !op.node.is_by_value()
+ )
{
let deref_kind = if checked_ty.is_box() {
"unboxing the value"
@@ -1549,9 +1561,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
return Some((
- span,
+ vec![(span, suggestion)],
message,
- suggestion,
Applicability::MachineApplicable,
true,
false,
@@ -1564,7 +1575,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
None
}
- pub fn check_for_cast(
+ pub fn suggest_cast(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
@@ -1721,7 +1732,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
];
(msg, suggestion)
} else {
- let msg = format!("{msg} and panic if the converted value doesn't fit");
+ let msg =
+ format!("{} and panic if the converted value doesn't fit", msg.clone());
let mut suggestion = sugg.clone();
suggestion.push((
expr.span.shrink_to_hi(),
@@ -1729,19 +1741,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
));
(msg, suggestion)
};
- err.multipart_suggestion_verbose(
- &msg,
- suggestion,
- Applicability::MachineApplicable,
- );
+ err.multipart_suggestion_verbose(msg, suggestion, Applicability::MachineApplicable);
};
let suggest_to_change_suffix_or_into =
|err: &mut Diagnostic,
found_to_exp_is_fallible: bool,
exp_to_found_is_fallible: bool| {
- let exp_is_lhs =
- expected_ty_expr.map(|e| self.tcx.hir().is_lhs(e.hir_id)).unwrap_or(false);
+ let exp_is_lhs = expected_ty_expr.is_some_and(|e| self.tcx.hir().is_lhs(e.hir_id));
if exp_is_lhs {
return;
@@ -1750,13 +1757,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let always_fallible = found_to_exp_is_fallible
&& (exp_to_found_is_fallible || expected_ty_expr.is_none());
let msg = if literal_is_ty_suffixed(expr) {
- &lit_msg
+ lit_msg.clone()
} else if always_fallible && (is_negative_int(expr) && is_uint(expected_ty)) {
// We now know that converting either the lhs or rhs is fallible. Before we
// suggest a fallible conversion, check if the value can never fit in the
// expected type.
let msg = format!("`{src}` cannot fit into type `{expected_ty}`");
- err.note(&msg);
+ err.note(msg);
return;
} else if in_const_context {
// Do not recommend `into` or `try_into` in const contexts.
@@ -1764,7 +1771,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else if found_to_exp_is_fallible {
return suggest_fallible_into_or_lhs_from(err, exp_to_found_is_fallible);
} else {
- &msg
+ msg.clone()
};
let suggestion = if literal_is_ty_suffixed(expr) {
suffix_suggestion.clone()
@@ -1826,14 +1833,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggest_to_change_suffix_or_into(err, false, true);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else if can_cast {
// Missing try_into implementation for `f64` to `f32`
err.multipart_suggestion_verbose(
- &format!("{cast_msg}, producing the closest possible value"),
+ format!("{cast_msg}, producing the closest possible value"),
cast_suggestion,
Applicability::MaybeIncorrect, // lossy conversion
);
@@ -1843,14 +1850,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(&ty::Uint(_) | &ty::Int(_), &ty::Float(_)) => {
if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else if can_cast {
// Missing try_into implementation for `{float}` to `{integer}`
err.multipart_suggestion_verbose(
- &format!("{msg}, rounding the float towards zero"),
+ format!("{msg}, rounding the float towards zero"),
cast_suggestion,
Applicability::MaybeIncorrect, // lossy conversion
);
@@ -1861,7 +1868,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// if `found` is `None` (meaning found is `usize`), don't suggest `.into()`
if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{msg}, producing the floating point representation of the integer",
),
into_suggestion,
@@ -1869,14 +1876,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else {
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{cast_msg}, producing the floating point representation of the integer, \
rounded if necessary",
),
@@ -1890,23 +1897,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// if `found` is `None` (meaning found is `isize`), don't suggest `.into()`
if exp.bit_width() > found.bit_width().unwrap_or(256) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{}, producing the floating point representation of the integer",
- &msg,
+ msg.clone(),
),
into_suggestion,
Applicability::MachineApplicable,
);
} else if literal_is_ty_suffixed(expr) {
err.multipart_suggestion_verbose(
- &lit_msg,
+ lit_msg,
suffix_suggestion,
Applicability::MachineApplicable,
);
} else {
// Missing try_into implementation for `{integer}` to `{float}`
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{}, producing the floating point representation of the integer, \
rounded if necessary",
&msg,
@@ -1923,7 +1930,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&ty::Char,
) => {
err.multipart_suggestion_verbose(
- &format!("{cast_msg}, since a `char` always occupies 4 bytes"),
+ format!("{cast_msg}, since a `char` always occupies 4 bytes"),
cast_suggestion,
Applicability::MachineApplicable,
);
@@ -1934,7 +1941,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Identify when the user has written `foo..bar()` instead of `foo.bar()`.
- pub fn check_for_range_as_method_call(
+ pub fn suggest_method_call_on_range_literal(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'tcx>,
@@ -2003,7 +2010,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Identify when the type error is because `()` is found in a binding that was assigned a
/// block without a tail expression.
- fn check_for_binding_assigned_block_without_tail_expression(
+ fn suggest_return_binding_for_missing_tail_expr(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
@@ -2045,7 +2052,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_wrong_return_type_due_to_generic_arg(
+ fn note_wrong_return_ty_due_to_generic_arg(
&self,
err: &mut Diagnostic,
expr: &hir::Expr<'_>,
diff --git a/compiler/rustc_hir_typeck/src/errors.rs b/compiler/rustc_hir_typeck/src/errors.rs
index 3eee2278d..4222205c8 100644
--- a/compiler/rustc_hir_typeck/src/errors.rs
+++ b/compiler/rustc_hir_typeck/src/errors.rs
@@ -1,4 +1,6 @@
//! Errors emitted by `rustc_hir_typeck`.
+use std::borrow::Cow;
+
use crate::fluent_generated as fluent;
use rustc_errors::{AddToDiagnostic, Applicability, Diagnostic, MultiSpan, SubdiagnosticMessage};
use rustc_macros::{Diagnostic, Subdiagnostic};
@@ -47,8 +49,8 @@ pub struct StructExprNonExhaustive {
}
#[derive(Diagnostic)]
-#[diag(hir_typeck_method_call_on_unknown_type, code = "E0699")]
-pub struct MethodCallOnUnknownType {
+#[diag(hir_typeck_method_call_on_unknown_raw_pointee, code = "E0699")]
+pub struct MethodCallOnUnknownRawPointee {
#[primary_span]
pub span: Span,
}
@@ -108,7 +110,7 @@ pub enum ExpectedReturnTypeLabel<'tcx> {
#[derive(Diagnostic)]
#[diag(hir_typeck_missing_parentheses_in_range, code = "E0689")]
-pub struct MissingParentheseInRange {
+pub struct MissingParenthesesInRange {
#[primary_span]
#[label(hir_typeck_missing_parentheses_in_range)]
pub span: Span,
@@ -228,3 +230,100 @@ impl HelpUseLatestEdition {
}
}
}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_const_select_must_be_const)]
+#[help]
+pub struct ConstSelectMustBeConst {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_const_select_must_be_fn)]
+#[note]
+#[help]
+pub struct ConstSelectMustBeFn<'a> {
+ #[primary_span]
+ pub span: Span,
+ pub ty: Ty<'a>,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_union_pat_multiple_fields)]
+pub struct UnionPatMultipleFields {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_union_pat_dotdot)]
+pub struct UnionPatDotDot {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_arg_mismatch_indeterminate)]
+pub struct ArgMismatchIndeterminate {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
+pub enum SuggestBoxing {
+ #[note(hir_typeck_suggest_boxing_note)]
+ #[multipart_suggestion(
+ hir_typeck_suggest_boxing_when_appropriate,
+ applicability = "machine-applicable"
+ )]
+ Unit {
+ #[suggestion_part(code = "Box::new(())")]
+ start: Span,
+ #[suggestion_part(code = "")]
+ end: Span,
+ },
+ #[note(hir_typeck_suggest_boxing_note)]
+ AsyncBody,
+ #[note(hir_typeck_suggest_boxing_note)]
+ #[multipart_suggestion(
+ hir_typeck_suggest_boxing_when_appropriate,
+ applicability = "machine-applicable"
+ )]
+ Other {
+ #[suggestion_part(code = "Box::new(")]
+ start: Span,
+ #[suggestion_part(code = ")")]
+ end: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_no_associated_item, code = "E0599")]
+pub struct NoAssociatedItem {
+ #[primary_span]
+ pub span: Span,
+ pub item_kind: &'static str,
+ pub item_name: Ident,
+ pub ty_prefix: Cow<'static, str>,
+ pub ty_str: String,
+ pub trait_missing_method: bool,
+}
+
+#[derive(Subdiagnostic)]
+#[note(hir_typeck_candidate_trait_note)]
+pub struct CandidateTraitNote {
+ #[primary_span]
+ pub span: Span,
+ pub trait_name: String,
+ pub item_name: Ident,
+ pub action_or_ty: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(hir_typeck_ctor_is_private, code = "E0603")]
+pub struct CtorIsPrivate {
+ #[primary_span]
+ pub span: Span,
+ pub def: String,
+}
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 6ffa0134f..19ff77d83 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -38,6 +38,7 @@ use rustc_infer::infer;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::InferOk;
+use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
use rustc_middle::middle::stability;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, AllowTwoPhase};
@@ -53,6 +54,8 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_target::abi::FieldIdx;
use rustc_target::spec::abi::Abi::RustIntrinsic;
use rustc_trait_selection::infer::InferCtxtExt;
+use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
+use rustc_trait_selection::traits::ObligationCtxt;
use rustc_trait_selection::traits::{self, ObligationCauseCode};
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
@@ -306,6 +309,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.deferred_asm_checks.borrow_mut().push((asm, expr.hir_id));
self.check_expr_asm(asm)
}
+ ExprKind::OffsetOf(container, ref fields) => {
+ self.check_offset_of(container, fields, expr)
+ }
ExprKind::Break(destination, ref expr_opt) => {
self.check_expr_break(destination, expr_opt.as_deref(), expr)
}
@@ -491,7 +497,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.borrow()
.adjustments()
.get(base.hir_id)
- .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
+ .is_some_and(|x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_))))
});
if !is_named {
self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span });
@@ -715,7 +721,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// ICE this expression in particular (see #43162).
if let ExprKind::Path(QPath::Resolved(_, path)) = e.kind {
if path.segments.len() == 1 && path.segments[0].ident.name == sym::rust {
- fatally_break_rust(self.tcx.sess);
+ fatally_break_rust(self.tcx);
}
}
}
@@ -1239,6 +1245,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error,
Some((rcvr, args)),
expected,
+ false,
) {
err.emit();
}
@@ -1420,6 +1427,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.check_repeat_element_needs_copy_bound(element, count, element_ty);
+ self.register_wf_obligation(
+ tcx.mk_array_with_const_len(t, count).into(),
+ expr.span,
+ traits::WellFormed(None),
+ );
+
tcx.mk_array_with_const_len(t, count)
}
@@ -1735,10 +1748,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {
let base_ty = self.typeck_results.borrow().expr_ty(*base_expr);
- let same_adt = match (adt_ty.kind(), base_ty.kind()) {
- (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt => true,
- _ => false,
- };
+ let same_adt = matches!((adt_ty.kind(), base_ty.kind()),
+ (ty::Adt(adt, _), ty::Adt(base_adt, _)) if adt == base_adt);
if self.tcx.sess.is_nightly_build() && same_adt {
feature_err(
&self.tcx.sess.parse_sess,
@@ -1940,12 +1951,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
private_fields: Vec<&ty::FieldDef>,
used_fields: &'tcx [hir::ExprField<'tcx>],
) {
- let mut err = self.tcx.sess.struct_span_err(
- span,
- &format!(
- "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
- ),
- );
+ let mut err =
+ self.tcx.sess.struct_span_err(
+ span,
+ format!(
+ "cannot construct `{adt_ty}` with struct literal syntax due to private fields",
+ ),
+ );
let (used_private_fields, remaining_private_fields): (
Vec<(Symbol, Span, bool)>,
Vec<(Symbol, Span, bool)>,
@@ -2041,7 +2053,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
- &format!(
+ format!(
"`{adt}::{variant}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
variant = variant.name,
@@ -2059,7 +2071,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(field.ident.span, "field does not exist");
err.span_suggestion_verbose(
expr_span,
- &format!(
+ format!(
"`{adt}` is a tuple {kind_name}, use the appropriate syntax",
adt = ty,
kind_name = kind_name,
@@ -2101,7 +2113,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let available_field_names =
self.available_field_names(variant, expr_span);
if !available_field_names.is_empty() {
- err.note(&format!(
+ err.note(format!(
"available fields are: {}",
self.name_series_display(available_field_names)
));
@@ -2380,7 +2392,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if add_label {
- err.span_label(field_ident.span, &format!("field not found in `{ty}`"));
+ err.span_label(field_ident.span, format!("field not found in `{ty}`"));
}
}
@@ -2449,22 +2461,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
base_did: DefId,
return_ty: Option<Ty<'tcx>>,
) -> ErrorGuaranteed {
- let struct_path = self.tcx().def_path_str(base_did);
- let kind_name = self.tcx().def_descr(base_did);
- let mut err = struct_span_err!(
- self.tcx().sess,
- field.span,
- E0616,
- "field `{field}` of {kind_name} `{struct_path}` is private",
- );
- err.span_label(field.span, "private field");
+ let mut err = self.private_field_err(field, base_did);
+
// Also check if an accessible method exists, which is often what is meant.
if self.method_exists(field, expr_t, expr.hir_id, false, return_ty)
&& !self.expr_in_place(expr.hir_id)
{
self.suggest_method_call(
&mut err,
- &format!("a method `{field}` also exists, call it with parentheses"),
+ format!("a method `{field}` also exists, call it with parentheses"),
field,
expr_t,
expr,
@@ -2568,7 +2573,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let param_span = self.tcx.hir().span(param_hir_id);
let param_name = self.tcx.hir().ty_param_name(param_def_id.expect_local());
- err.span_label(param_span, &format!("type parameter '{param_name}' declared here"));
+ err.span_label(param_span, format!("type parameter '{param_name}' declared here"));
}
fn suggest_fields_on_recordish(
@@ -2592,7 +2597,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let struct_variant_def = def.non_enum_variant();
let field_names = self.available_field_names(struct_variant_def, access_span);
if !field_names.is_empty() {
- err.note(&format!(
+ err.note(format!(
"available fields are: {}",
self.name_series_display(field_names),
));
@@ -2633,7 +2638,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if let Ok(base) = self.tcx.sess.source_map().span_to_snippet(base.span) {
let msg = format!("`{base}` is a raw pointer; try dereferencing it");
let suggestion = format!("(*{base}).{field}");
- err.span_suggestion(expr.span, &msg, suggestion, Applicability::MaybeIncorrect);
+ err.span_suggestion(expr.span, msg, suggestion, Applicability::MaybeIncorrect);
}
}
@@ -2697,6 +2702,24 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err
}
+ fn private_field_err(
+ &self,
+ field: Ident,
+ base_did: DefId,
+ ) -> DiagnosticBuilder<'_, ErrorGuaranteed> {
+ let struct_path = self.tcx().def_path_str(base_did);
+ let kind_name = self.tcx().def_descr(base_did);
+ let mut err = struct_span_err!(
+ self.tcx().sess,
+ field.span,
+ E0616,
+ "field `{field}` of {kind_name} `{struct_path}` is private",
+ );
+ err.span_label(field.span, "private field");
+
+ err
+ }
+
pub(crate) fn get_field_candidates_considering_privacy(
&self,
span: Span,
@@ -2802,6 +2825,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
element_ty
}
None => {
+ // Attempt to *shallowly* search for an impl which matches,
+ // but has nested obligations which are unsatisfied.
+ for (base_t, _) in self.autoderef(base.span, base_t).silence_errors() {
+ if let Some((_, index_ty, element_ty)) =
+ self.find_and_report_unsatisfied_index_impl(base, base_t)
+ {
+ self.demand_coerce(idx, idx_t, index_ty, None, AllowTwoPhase::No);
+ return element_ty;
+ }
+ }
+
let mut err = type_error_struct!(
self.tcx.sess,
expr.span,
@@ -2845,6 +2879,89 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
+ /// Try to match an implementation of `Index` against a self type, and report
+ /// the unsatisfied predicates that result from confirming this impl.
+ ///
+ /// Given an index expression, sometimes the `Self` type shallowly but does not
+ /// deeply satisfy an impl predicate. Instead of simply saying that the type
+ /// does not support being indexed, we want to point out exactly what nested
+ /// predicates cause this to be, so that the user can add them to fix their code.
+ fn find_and_report_unsatisfied_index_impl(
+ &self,
+ base_expr: &hir::Expr<'_>,
+ base_ty: Ty<'tcx>,
+ ) -> Option<(ErrorGuaranteed, Ty<'tcx>, Ty<'tcx>)> {
+ let index_trait_def_id = self.tcx.lang_items().index_trait()?;
+ let index_trait_output_def_id = self.tcx.get_diagnostic_item(sym::IndexOutput)?;
+
+ let mut relevant_impls = vec![];
+ self.tcx.for_each_relevant_impl(index_trait_def_id, base_ty, |impl_def_id| {
+ relevant_impls.push(impl_def_id);
+ });
+ let [impl_def_id] = relevant_impls[..] else {
+ // Only report unsatisfied impl predicates if there's one impl
+ return None;
+ };
+
+ self.commit_if_ok(|_| {
+ let ocx = ObligationCtxt::new_in_snapshot(self);
+ let impl_substs = self.fresh_substs_for_item(base_expr.span, impl_def_id);
+ let impl_trait_ref =
+ self.tcx.impl_trait_ref(impl_def_id).unwrap().subst(self.tcx, impl_substs);
+ let cause = self.misc(base_expr.span);
+
+ // Match the impl self type against the base ty. If this fails,
+ // we just skip this impl, since it's not particularly useful.
+ let impl_trait_ref = ocx.normalize(&cause, self.param_env, impl_trait_ref);
+ ocx.eq(&cause, self.param_env, impl_trait_ref.self_ty(), base_ty)?;
+
+ // Register the impl's predicates. One of these predicates
+ // must be unsatisfied, or else we wouldn't have gotten here
+ // in the first place.
+ ocx.register_obligations(traits::predicates_for_generics(
+ |idx, span| {
+ cause.clone().derived_cause(
+ ty::Binder::dummy(ty::TraitPredicate {
+ trait_ref: impl_trait_ref,
+ polarity: ty::ImplPolarity::Positive,
+ constness: ty::BoundConstness::NotConst,
+ }),
+ |derived| {
+ traits::ImplDerivedObligation(Box::new(
+ traits::ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: impl_def_id,
+ impl_def_predicate_index: Some(idx),
+ span,
+ },
+ ))
+ },
+ )
+ },
+ self.param_env,
+ self.tcx.predicates_of(impl_def_id).instantiate(self.tcx, impl_substs),
+ ));
+
+ // Normalize the output type, which we can use later on as the
+ // return type of the index expression...
+ let element_ty = ocx.normalize(
+ &cause,
+ self.param_env,
+ self.tcx.mk_projection(index_trait_output_def_id, impl_trait_ref.substs),
+ );
+
+ let errors = ocx.select_where_possible();
+ // There should be at least one error reported. If not, we
+ // will still delay a span bug in `report_fulfillment_errors`.
+ Ok::<_, NoSolution>((
+ self.err_ctxt().report_fulfillment_errors(&errors),
+ impl_trait_ref.substs.type_at(1),
+ element_ty,
+ ))
+ })
+ .ok()
+ }
+
fn point_at_index_if_possible(
&self,
errors: &mut Vec<traits::FulfillmentError<'tcx>>,
@@ -2954,4 +3071,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.mk_unit()
}
}
+
+ fn check_offset_of(
+ &self,
+ container: &'tcx hir::Ty<'tcx>,
+ fields: &[Ident],
+ expr: &'tcx hir::Expr<'tcx>,
+ ) -> Ty<'tcx> {
+ let container = self.to_ty(container).normalized;
+
+ let mut field_indices = Vec::with_capacity(fields.len());
+ let mut current_container = container;
+
+ for &field in fields {
+ let container = self.structurally_resolved_type(expr.span, current_container);
+
+ match container.kind() {
+ ty::Adt(container_def, substs) if !container_def.is_enum() => {
+ let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id);
+ let (ident, def_scope) =
+ self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block);
+
+ let fields = &container_def.non_enum_variant().fields;
+ if let Some((index, field)) = fields
+ .iter_enumerated()
+ .find(|(_, f)| f.ident(self.tcx).normalize_to_macros_2_0() == ident)
+ {
+ let field_ty = self.field_ty(expr.span, field, substs);
+
+ // FIXME: DSTs with static alignment should be allowed
+ self.require_type_is_sized(field_ty, expr.span, traits::MiscObligation);
+
+ if field.vis.is_accessible_from(def_scope, self.tcx) {
+ self.tcx.check_stability(field.did, Some(expr.hir_id), expr.span, None);
+ } else {
+ self.private_field_err(ident, container_def.did()).emit();
+ }
+
+ // Save the index of all fields regardless of their visibility in case
+ // of error recovery.
+ field_indices.push(index);
+ current_container = field_ty;
+
+ continue;
+ }
+ }
+ ty::Tuple(tys) => {
+ let fstr = field.as_str();
+
+ if let Ok(index) = fstr.parse::<usize>() {
+ if fstr == index.to_string() {
+ if let Some(&field_ty) = tys.get(index) {
+ field_indices.push(index.into());
+ current_container = field_ty;
+
+ continue;
+ }
+ }
+ }
+ }
+ _ => (),
+ };
+
+ self.no_such_field_err(field, container, expr.hir_id).emit();
+
+ break;
+ }
+
+ self.typeck_results
+ .borrow_mut()
+ .offset_of_data_mut()
+ .insert(expr.hir_id, (container, field_indices));
+
+ self.tcx.types.usize
+ }
}
diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
index ee1c6fbfd..e14e8ac2c 100644
--- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
+++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs
@@ -300,6 +300,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
hir::ExprKind::Continue(..)
| hir::ExprKind::Lit(..)
| hir::ExprKind::ConstBlock(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Err(_) => {}
hir::ExprKind::Loop(blk, ..) => {
@@ -437,12 +438,19 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> {
// to borrow discr.
needs_to_be_read = true;
}
- PatKind::Or(_)
- | PatKind::Box(_)
- | PatKind::Slice(..)
- | PatKind::Ref(..)
- | PatKind::Wild => {
- // If the PatKind is Or, Box, Slice or Ref, the decision is made later
+ PatKind::Slice(lhs, wild, rhs) => {
+ // We don't need to test the length if the pattern is `[..]`
+ if matches!((lhs, wild, rhs), (&[], Some(_), &[]))
+ // Arrays have a statically known size, so
+ // there is no need to read their length
+ || discr_place.place.base_ty.is_array()
+ {
+ } else {
+ needs_to_be_read = true;
+ }
+ }
+ PatKind::Or(_) | PatKind::Box(_) | PatKind::Ref(..) | PatKind::Wild => {
+ // If the PatKind is Or, Box, or Ref, the decision is made later
// as these patterns contains subpatterns
// If the PatKind is Wild, the decision is made based on the other patterns being
// examined
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
index f736f7a96..557950338 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs
@@ -1,10 +1,11 @@
use crate::callee::{self, DeferredCallResolution};
+use crate::errors::CtorIsPrivate;
use crate::method::{self, MethodCallee, SelfSource};
use crate::rvalue_scopes;
use crate::{BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, RawTy};
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashSet;
-use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan};
+use rustc_errors::{Applicability, Diagnostic, ErrorGuaranteed, MultiSpan, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::DefId;
@@ -35,7 +36,9 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Span;
use rustc_target::abi::FieldIdx;
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt as _;
-use rustc_trait_selection::traits::{self, NormalizeExt, ObligationCauseCode, ObligationCtxt};
+use rustc_trait_selection::traits::{
+ self, NormalizeExt, ObligationCauseCode, ObligationCtxt, StructurallyNormalizeExt,
+};
use std::collections::hash_map::Entry;
use std::slice;
@@ -63,9 +66,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint::builtin::UNREACHABLE_CODE,
id,
span,
- &msg,
+ msg.clone(),
|lint| {
- lint.span_label(span, &msg).span_label(
+ lint.span_label(span, msg).span_label(
orig_span,
custom_note
.unwrap_or("any code following this expression is unreachable"),
@@ -275,7 +278,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
self.tcx.sess.delay_span_bug(
expr.span,
- &format!(
+ format!(
"while adjusting {:?}, can't compose {:?} and {:?}",
expr,
entry.get(),
@@ -420,9 +423,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ast_c: &hir::AnonConst,
param_def_id: DefId,
) -> ty::Const<'tcx> {
- let const_def =
- ty::WithOptConstParam { did: ast_c.def_id, const_param_did: Some(param_def_id) };
- let c = ty::Const::from_opt_const_arg_anon_const(self.tcx, const_def);
+ let did = ast_c.def_id;
+ self.tcx.feed_anon_const_type(did, self.tcx.type_of(param_def_id));
+ let c = ty::Const::from_anon_const(self.tcx, did);
self.register_wf_obligation(
c.into(),
self.tcx.hir().span(ast_c.hir_id),
@@ -827,7 +830,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
QPath::TypeRelative(ref qself, ref segment) => {
// Don't use `self.to_ty`, since this will register a WF obligation.
- // If we're trying to call a non-existent method on a trait
+ // If we're trying to call a nonexistent method on a trait
// (e.g. `MyTrait::missing_method`), then resolution will
// give us a `QPath::TypeRelative` with a trait object as
// `qself`. In that case, we want to avoid registering a WF obligation
@@ -853,23 +856,47 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let item_name = item_segment.ident;
let result = self
.resolve_fully_qualified_call(span, item_name, ty.normalized, qself.span, hir_id)
+ .and_then(|r| {
+ // lint bare trait if the method is found in the trait
+ if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+ diag.emit();
+ }
+ Ok(r)
+ })
.or_else(|error| {
+ let guar = self
+ .tcx
+ .sess
+ .delay_span_bug(span, "method resolution should've emitted an error");
let result = match error {
method::MethodError::PrivateMatch(kind, def_id, _) => Ok((kind, def_id)),
- _ => Err(ErrorGuaranteed::unchecked_claim_error_was_emitted()),
+ _ => Err(guar),
};
+ let trait_missing_method =
+ matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait();
// If we have a path like `MyTrait::missing_method`, then don't register
// a WF obligation for `dyn MyTrait` when method lookup fails. Otherwise,
// register a WF obligation so that we can detect any additional
// errors in the self type.
- if !(matches!(error, method::MethodError::NoMatch(_)) && ty.normalized.is_trait()) {
+ if !trait_missing_method {
self.register_wf_obligation(
ty.raw.into(),
qself.span,
traits::WellFormed(None),
);
}
+
+ // emit or cancel the diagnostic for bare traits
+ if span.edition().rust_2021() && let Some(mut diag) = self.tcx.sess.diagnostic().steal_diagnostic(qself.span, StashKey::TraitMissingMethod) {
+ if trait_missing_method {
+ // cancel the diag for bare traits when meeting `MyTrait::missing_method`
+ diag.cancel();
+ } else {
+ diag.emit();
+ }
+ }
+
if item_name.name != kw::Empty {
if let Some(mut e) = self.report_method_error(
span,
@@ -879,10 +906,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error,
None,
Expectation::NoExpectation,
+ trait_missing_method && span.edition().rust_2021(), // emits missing method for trait only after edition 2021
) {
e.emit();
}
}
+
result
});
@@ -989,8 +1018,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.typeck_results
.borrow()
.expr_ty_adjusted_opt(rcvr)
- .and_then(|ty| expected.map(|expected_ty| expected_ty.peel_refs() == ty.peel_refs()))
- .unwrap_or(false);
+ .zip(expected)
+ .is_some_and(|(ty, expected_ty)| expected_ty.peel_refs() == ty.peel_refs());
let prev_call_mutates_and_returns_unit = || {
self.typeck_results
@@ -998,14 +1027,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
.type_dependent_def_id(expr.hir_id)
.map(|def_id| self.tcx.fn_sig(def_id).skip_binder().skip_binder())
.and_then(|sig| sig.inputs_and_output.split_last())
- .map(|(output, inputs)| {
+ .is_some_and(|(output, inputs)| {
output.is_unit()
&& inputs
.get(0)
.and_then(|self_ty| self_ty.ref_mutability())
- .map_or(false, rustc_ast::Mutability::is_mut)
+ .is_some_and(rustc_ast::Mutability::is_mut)
})
- .unwrap_or(false)
};
if !(rcvr_has_the_expected_type || prev_call_mutates_and_returns_unit()) {
@@ -1034,15 +1062,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
rcvr.span,
"you probably want to use this value after calling the method...",
);
- err.span_note(sp, &modifies_rcvr_note);
- err.note(&format!("...instead of the `()` output of method `{}`", path_segment.ident));
+ err.span_note(sp, modifies_rcvr_note);
+ err.note(format!("...instead of the `()` output of method `{}`", path_segment.ident));
} else if let ExprKind::MethodCall(..) = rcvr.kind {
err.span_note(
sp,
modifies_rcvr_note.clone() + ", it is not meant to be used in method chains.",
);
} else {
- err.span_note(sp, &modifies_rcvr_note);
+ err.span_note(sp, modifies_rcvr_note);
}
}
@@ -1172,16 +1200,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let has_self = path_segs
- .last()
- .map(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self)
- .unwrap_or(false);
+ let has_self =
+ path_segs.last().is_some_and(|PathSeg(def_id, _)| tcx.generics_of(*def_id).has_self);
let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res {
let ty = self.handle_raw_ty(span, tcx.at(span).type_of(impl_def_id).subst_identity());
match ty.normalized.ty_adt_def() {
Some(adt_def) if adt_def.has_ctor() => {
let (ctor_kind, ctor_def_id) = adt_def.non_enum_variant().ctor.unwrap();
+ // Check the visibility of the ctor.
+ let vis = tcx.visibility(ctor_def_id);
+ if !vis.is_accessible_from(tcx.parent_module(hir_id).to_def_id(), tcx) {
+ tcx.sess
+ .emit_err(CtorIsPrivate { span, def: tcx.def_path_str(adt_def.did()) });
+ }
let new_res = Res::Def(DefKind::Ctor(CtorOf::Struct, ctor_kind), ctor_def_id);
let user_substs = Self::user_substs_for_adt(ty);
user_self_ty = user_substs.user_self_ty;
@@ -1374,7 +1406,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Err(_) => {
self.tcx.sess.delay_span_bug(
span,
- &format!(
+ format!(
"instantiate_value_path: (UFCS) {:?} was a subtype of {:?} but now is not?",
self_ty,
impl_ty,
@@ -1434,10 +1466,33 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
/// Resolves `typ` by a single level if `typ` is a type variable.
+ ///
+ /// When the new solver is enabled, this will also attempt to normalize
+ /// the type if it's a projection (note that it will not deeply normalize
+ /// projections within the type, just the outermost layer of the type).
+ ///
/// If no resolution is possible, then an error is reported.
/// Numeric inference variables may be left unresolved.
pub fn structurally_resolved_type(&self, sp: Span, ty: Ty<'tcx>) -> Ty<'tcx> {
- let ty = self.resolve_vars_with_obligations(ty);
+ let mut ty = self.resolve_vars_with_obligations(ty);
+
+ if self.tcx.trait_solver_next()
+ && let ty::Alias(ty::Projection, _) = ty.kind()
+ {
+ match self
+ .at(&self.misc(sp), self.param_env)
+ .structurally_normalize(ty, &mut **self.fulfillment_cx.borrow_mut())
+ {
+ Ok(normalized_ty) => {
+ ty = normalized_ty;
+ },
+ Err(errors) => {
+ let guar = self.err_ctxt().report_fulfillment_errors(&errors);
+ return self.tcx.ty_error(guar);
+ }
+ }
+ }
+
if !ty.is_ty_var() {
ty
} else {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
index f879ccbb3..3efdab534 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/adjust_fulfillment_errors.rs
@@ -164,24 +164,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
for param in
[param_to_point_at, fallback_param_to_point_at, self_param_to_point_at]
+ .into_iter()
+ .flatten()
{
- if let Some(param) = param {
- let refined_expr = self.point_at_field_if_possible(
- def_id,
- param,
- variant_def_id,
- fields,
- );
-
- match refined_expr {
- None => {}
- Some((refined_expr, _)) => {
- error.obligation.cause.span = refined_expr
- .span
- .find_ancestor_in_same_ctxt(error.obligation.cause.span)
- .unwrap_or(refined_expr.span);
- return true;
- }
+ let refined_expr =
+ self.point_at_field_if_possible(def_id, param, variant_def_id, fields);
+
+ match refined_expr {
+ None => {}
+ Some((refined_expr, _)) => {
+ error.obligation.cause.span = refined_expr
+ .span
+ .find_ancestor_in_same_ctxt(error.obligation.cause.span)
+ .unwrap_or(refined_expr.span);
+ return true;
}
}
}
@@ -282,9 +278,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span: Span,
) -> bool {
if let traits::FulfillmentErrorCode::CodeSelectionError(
- traits::SelectionError::OutputTypeParameterMismatch(_, expected, _),
+ traits::SelectionError::OutputTypeParameterMismatch(box traits::SelectionOutputTypeParameterMismatch{
+ expected_trait_ref, ..
+ }),
) = error.code
- && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected.skip_binder().self_ty().kind()
+ && let ty::Closure(def_id, _) | ty::Generator(def_id, ..) = expected_trait_ref.skip_binder().self_ty().kind()
&& span.overlaps(self.tcx.def_span(*def_id))
{
true
@@ -334,7 +332,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// expression mentioned.
///
/// `blame_specific_arg_if_possible` will find the most-specific expression anywhere inside
- /// the provided function call expression, and mark it as responsible for the fullfillment
+ /// the provided function call expression, and mark it as responsible for the fulfillment
/// error.
fn blame_specific_arg_if_possible(
&self,
@@ -485,7 +483,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// For the purposes of this function, we hope that it is a `struct` type, and that our current `expr` is a literal of
// that struct type.
let impl_trait_self_ref = if self.tcx.is_trait_alias(obligation.impl_or_alias_def_id) {
- self.tcx.mk_trait_ref(
+ ty::TraitRef::new(
+ self.tcx,
obligation.impl_or_alias_def_id,
ty::InternalSubsts::identity_for_item(self.tcx, obligation.impl_or_alias_def_id),
)
@@ -846,7 +845,7 @@ fn find_param_in_ty<'tcx>(
return true;
}
if let ty::GenericArgKind::Type(ty) = arg.unpack()
- && let ty::Alias(ty::Projection, ..) = ty.kind()
+ && let ty::Alias(ty::Projection | ty::Inherent, ..) = ty.kind()
{
// This logic may seem a bit strange, but typically when
// we have a projection type in a function signature, the
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
index 6f26afcaf..d45e3d395 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/arg_matrix.rs
@@ -1,6 +1,6 @@
use std::cmp;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::error::TypeError;
rustc_index::newtype_index! {
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index ea1b52daa..eba5c829e 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -2,8 +2,8 @@ use crate::coercion::CoerceMany;
use crate::fn_ctxt::arg_matrix::{ArgMatrix, Compatibility, Error, ExpectedIdx, ProvidedIdx};
use crate::gather_locals::Declaration;
use crate::method::MethodCallee;
-use crate::Expectation::*;
use crate::TupleArgumentsFlag::*;
+use crate::{errors, Expectation::*};
use crate::{
struct_span_err, BreakableCtxt, Diverges, Expectation, FnCtxt, LocalTy, Needs, RawTy,
TupleArgumentsFlag,
@@ -21,7 +21,7 @@ use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::intrinsicck::InlineAsmCtxt;
use rustc_hir_analysis::check::potentially_plural_count;
use rustc_hir_analysis::structured_errors::StructuredDiagnostic;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_infer::infer::error_reporting::{FailureCode, ObligationCauseExt};
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::TypeTrace;
@@ -283,19 +283,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if idx == 1 && !self.tcx.is_const_fn_raw(*def_id) {
self.tcx
.sess
- .struct_span_err(provided_arg.span, "this argument must be a `const fn`")
- .help("consult the documentation on `const_eval_select` for more information")
- .emit();
+ .emit_err(errors::ConstSelectMustBeConst { span: provided_arg.span });
}
} else {
- self.tcx
- .sess
- .struct_span_err(provided_arg.span, "this argument must be a function item")
- .note(format!("expected a function item, found {checked_ty}"))
- .help(
- "consult the documentation on `const_eval_select` for more information",
- )
- .emit();
+ self.tcx.sess.emit_err(errors::ConstSelectMustBeFn {
+ span: provided_arg.span,
+ ty: checked_ty,
+ });
}
}
@@ -368,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
continue;
}
- let is_closure = matches!(arg.kind, ExprKind::Closure { .. });
+ // For this check, we do *not* want to treat async generator closures (async blocks)
+ // as proper closures. Doing so would regress type inference when feeding
+ // the return value of an argument-position async block to an argument-position
+ // closure wrapped in a block.
+ // See <https://github.com/rust-lang/rust/issues/112225>.
+ let is_closure = if let ExprKind::Closure(closure) = arg.kind {
+ !tcx.generator_is_async(closure.def_id.to_def_id())
+ } else {
+ false
+ };
if is_closure != check_closures {
continue;
}
@@ -691,7 +694,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err = tcx.sess.struct_span_err_with_code(
full_call_span,
- &format!(
+ format!(
"{call_name} takes {}{} but {} {} supplied",
if c_variadic { "at least " } else { "" },
potentially_plural_count(
@@ -744,17 +747,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if cfg!(debug_assertions) {
span_bug!(error_span, "expected errors from argument matrix");
} else {
- tcx.sess
- .struct_span_err(
- error_span,
- "argument type mismatch was detected, \
- but rustc had trouble determining where",
- )
- .note(
- "we would appreciate a bug report: \
- https://github.com/rust-lang/rust/issues/new",
- )
- .emit();
+ tcx.sess.emit_err(errors::ArgMismatchIndeterminate { span: error_span });
}
return;
}
@@ -844,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
tcx.sess.struct_span_err_with_code(
full_call_span,
- &format!(
+ format!(
"this {} takes {}{} but {} {} supplied",
call_name,
if c_variadic { "at least " } else { "" },
@@ -892,7 +885,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut errors = errors.into_iter().peekable();
let mut only_extras_so_far = errors
.peek()
- .map_or(false, |first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
+ .is_some_and(|first| matches!(first, Error::Extra(arg_idx) if arg_idx.index() == 0));
let mut suggestions = vec![];
while let Some(error) = errors.next() {
only_extras_so_far &= matches!(error, Error::Extra(_));
@@ -1219,7 +1212,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
SuggestionText::Remove(plural) => {
err.multipart_suggestion(
- &format!("remove the extra argument{}", if plural { "s" } else { "" }),
+ format!("remove the extra argument{}", if plural { "s" } else { "" }),
suggestions,
Applicability::HasPlaceholders,
);
@@ -1269,7 +1262,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggestion += ")";
err.span_suggestion_verbose(
suggestion_span,
- &suggestion_text,
+ suggestion_text,
suggestion,
Applicability::HasPlaceholders,
);
@@ -1316,6 +1309,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
opt_ty.unwrap_or_else(|| self.next_float_var())
}
ast::LitKind::Bool(_) => tcx.types.bool,
+ ast::LitKind::CStr(_, _) => tcx.mk_imm_ref(
+ tcx.lifetimes.re_static,
+ tcx.type_of(tcx.require_lang_item(hir::LangItem::CStr, Some(lit.span)))
+ .skip_binder(),
+ ),
ast::LitKind::Err => tcx.ty_error_misc(),
}
}
@@ -1530,7 +1528,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// case we can ignore the tail expression (e.g., `'a: {
// break 'a 22; }` would not force the type of the block
// to be `()`).
- let tail_expr = blk.expr.as_ref();
let coerce_to_ty = expected.coercion_target_type(self, blk.span);
let coerce = if blk.targeted_by_break {
CoerceMany::new(coerce_to_ty)
@@ -1548,13 +1545,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// check the tail expression **without** holding the
// `enclosing_breakables` lock below.
- let tail_expr_ty = tail_expr.map(|t| self.check_expr_with_expectation(t, expected));
+ let tail_expr_ty =
+ blk.expr.map(|expr| (expr, self.check_expr_with_expectation(expr, expected)));
let mut enclosing_breakables = self.enclosing_breakables.borrow_mut();
let ctxt = enclosing_breakables.find_breakable(blk.hir_id);
let coerce = ctxt.coerce.as_mut().unwrap();
- if let Some(tail_expr_ty) = tail_expr_ty {
- let tail_expr = tail_expr.unwrap();
+ if let Some((tail_expr, tail_expr_ty)) = tail_expr_ty {
let span = self.get_expr_coercion_span(tail_expr);
let cause = self.cause(span, ObligationCauseCode::BlockTailExpression(blk.hir_id));
let ty_for_diagnostic = coerce.merged_ty();
@@ -1607,6 +1604,15 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&self.misc(sp),
&mut |err| {
if let Some(expected_ty) = expected.only_has_type(self) {
+ if blk.stmts.is_empty() && blk.expr.is_none() {
+ self.suggest_boxing_when_appropriate(
+ err,
+ blk.span,
+ blk.hir_id,
+ expected_ty,
+ self.tcx.mk_unit(),
+ );
+ }
if !self.consider_removing_semicolon(blk, expected_ty, err) {
self.err_ctxt().consider_returning_binding(
blk,
@@ -1619,7 +1625,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// silence this redundant error, as we already emit E0070.
// Our block must be a `assign desugar local; assignment`
- if let Some(hir::Node::Block(hir::Block {
+ if let hir::Block {
stmts:
[
hir::Stmt {
@@ -1641,7 +1647,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
],
..
- })) = self.tcx.hir().find(blk.hir_id)
+ } = blk
{
self.comes_from_while_condition(blk.hir_id, |_| {
err.downgrade_to_delayed_bug();
@@ -1911,7 +1917,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
_ => {
// Look for a user-provided impl of a `Fn` trait, and point to it.
let new_def_id = self.probe(|_| {
- let trait_ref = self.tcx.mk_trait_ref(
+ let trait_ref = ty::TraitRef::new(self.tcx,
call_kind.to_def_id(self.tcx),
[
callee_ty,
@@ -1963,7 +1969,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
spans.push_span_label(param.span, "");
}
- err.span_note(spans, &format!("{} defined here", self.tcx.def_descr(def_id)));
+ err.span_note(spans, format!("{} defined here", self.tcx.def_descr(def_id)));
} else if let Some(hir::Node::Expr(e)) = self.tcx.hir().get_if_local(def_id)
&& let hir::ExprKind::Closure(hir::Closure { body, .. }) = &e.kind
{
@@ -1974,11 +1980,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
("closure", self.tcx.def_span(def_id))
};
- err.span_note(span, &format!("{} defined here", kind));
+ err.span_note(span, format!("{} defined here", kind));
} else {
err.span_note(
self.tcx.def_span(def_id),
- &format!("{} defined here", self.tcx.def_descr(def_id)),
+ format!("{} defined here", self.tcx.def_descr(def_id)),
);
}
}
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
index c6fd0b610..67f45f9aa 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs
@@ -17,7 +17,6 @@ use rustc_infer::infer;
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::ty::subst::GenericArgKind;
use rustc_middle::ty::{self, Const, Ty, TyCtxt, TypeVisitableExt};
use rustc_session::Session;
use rustc_span::symbol::Ident;
@@ -169,7 +168,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ocx.normalize(&ObligationCause::dummy(), self.param_env, fn_sig);
if ocx.select_all_or_error().is_empty() {
let normalized_fn_sig = self.resolve_vars_if_possible(normalized_fn_sig);
- if !normalized_fn_sig.needs_infer() {
+ if !normalized_fn_sig.has_infer() {
return normalized_fn_sig;
}
}
@@ -250,16 +249,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
}
fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> {
- if let Some(param) = param {
- if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() {
- return ty;
- }
- unreachable!()
- } else {
- self.next_ty_var(TypeVariableOrigin {
+ match param {
+ Some(param) => self.var_for_def(span, param).as_type().unwrap(),
+ None => self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span,
- })
+ }),
}
}
@@ -269,16 +264,12 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
param: Option<&ty::GenericParamDef>,
span: Span,
) -> Const<'tcx> {
- if let Some(param) = param {
- if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() {
- return ct;
- }
- unreachable!()
- } else {
- self.next_const_var(
+ match param {
+ Some(param) => self.var_for_def(span, param).as_const().unwrap(),
+ None => self.next_const_var(
ty,
ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span },
- )
+ ),
}
}
@@ -309,7 +300,7 @@ impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> {
match ty.kind() {
ty::Adt(adt_def, _) => Some(*adt_def),
// FIXME(#104767): Should we handle bound regions here?
- ty::Alias(ty::Projection, _) if !ty.has_escaping_bound_vars() => {
+ ty::Alias(ty::Projection | ty::Inherent, _) if !ty.has_escaping_bound_vars() => {
self.normalize(span, ty).ty_adt_def()
}
_ => None,
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
index 5fda4e191..c4add4dbd 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs
@@ -1,6 +1,6 @@
use super::FnCtxt;
-use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel};
+use crate::errors::{AddReturnTypeSuggestion, ExpectedReturnTypeLabel, SuggestBoxing};
use crate::fluent_generated as fluent;
use crate::method::probe::{IsSuggestion, Mode, ProbeScope};
use rustc_ast::util::parser::{ExprPrecedence, PREC_POSTFIX};
@@ -9,7 +9,8 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind};
use rustc_hir::lang_items::LangItem;
use rustc_hir::{
- Expr, ExprKind, GenericBound, Node, Path, QPath, Stmt, StmtKind, TyKind, WherePredicate,
+ AsyncGeneratorKind, Expr, ExprKind, GeneratorKind, GenericBound, HirId, Node, Path, QPath,
+ Stmt, StmtKind, TyKind, WherePredicate,
};
use rustc_hir_analysis::astconv::AstConv;
use rustc_infer::traits::{self, StatementAsExpression};
@@ -274,13 +275,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected_ty_expr: Option<&'tcx hir::Expr<'tcx>>,
) -> bool {
let expr = expr.peel_blocks();
- if let Some((sp, msg, suggestion, applicability, verbose, annotation)) =
- self.check_ref(expr, found, expected)
+ if let Some((suggestion, msg, applicability, verbose, annotation)) =
+ self.suggest_deref_or_ref(expr, found, expected)
{
if verbose {
- err.span_suggestion_verbose(sp, &msg, suggestion, applicability);
+ err.multipart_suggestion_verbose(msg, suggestion, applicability);
} else {
- err.span_suggestion(sp, &msg, suggestion, applicability);
+ err.multipart_suggestion(msg, suggestion, applicability);
}
if annotation {
let suggest_annotation = match expr.peel_drop_temps().kind {
@@ -342,7 +343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_label(sp, format!("{descr} `{name}` defined here"));
}
return true;
- } else if self.check_for_cast(err, expr, found, expected, expected_ty_expr) {
+ } else if self.suggest_cast(err, expr, found, expected, expected_ty_expr) {
return true;
} else {
let methods = self.get_conversion_methods(expr.span, expected, found, expr.hir_id);
@@ -438,33 +439,32 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(in super::super) fn suggest_boxing_when_appropriate(
&self,
err: &mut Diagnostic,
- expr: &hir::Expr<'_>,
+ span: Span,
+ hir_id: HirId,
expected: Ty<'tcx>,
found: Ty<'tcx>,
) -> bool {
- if self.tcx.hir().is_inside_const_context(expr.hir_id) {
- // Do not suggest `Box::new` in const context.
- return false;
- }
- if !expected.is_box() || found.is_box() {
+ // Do not suggest `Box::new` in const context.
+ if self.tcx.hir().is_inside_const_context(hir_id) || !expected.is_box() || found.is_box() {
return false;
}
- let boxed_found = self.tcx.mk_box(found);
- if self.can_coerce(boxed_found, expected) {
- err.multipart_suggestion(
- "store this in the heap by calling `Box::new`",
- vec![
- (expr.span.shrink_to_lo(), "Box::new(".to_string()),
- (expr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- );
- err.note(
- "for more on the distinction between the stack and the heap, read \
- https://doc.rust-lang.org/book/ch15-01-box.html, \
- https://doc.rust-lang.org/rust-by-example/std/box.html, and \
- https://doc.rust-lang.org/std/boxed/index.html",
- );
+ if self.can_coerce(self.tcx.mk_box(found), expected) {
+ let suggest_boxing = match found.kind() {
+ ty::Tuple(tuple) if tuple.is_empty() => {
+ SuggestBoxing::Unit { start: span.shrink_to_lo(), end: span }
+ }
+ ty::Generator(def_id, ..)
+ if matches!(
+ self.tcx.generator_kind(def_id),
+ Some(GeneratorKind::Async(AsyncGeneratorKind::Closure))
+ ) =>
+ {
+ SuggestBoxing::AsyncBody
+ }
+ _ => SuggestBoxing::Other { start: span.shrink_to_lo(), end: span.shrink_to_hi() },
+ };
+ err.subdiagnostic(suggest_boxing);
+
true
} else {
false
@@ -794,7 +794,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return;
};
- // get all where BoundPredicates here, because they are used in to cases below
+ // get all where BoundPredicates here, because they are used in two cases below
let where_predicates = predicates
.iter()
.filter_map(|p| match p {
@@ -1096,10 +1096,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx,
self.misc(expr.span),
self.param_env,
- ty::Binder::dummy(self.tcx.mk_trait_ref(
+ ty::TraitRef::new(self.tcx,
into_def_id,
[expr_ty, expected_ty]
- )),
+ ),
))
{
let sugg = if expr.precedence().order() >= PREC_POSTFIX {
@@ -1252,7 +1252,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
node: rustc_ast::LitKind::Int(lit, rustc_ast::LitIntType::Unsuffixed),
span,
}) => {
- let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) else { return false; };
+ let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(*span) else { return false; };
if !(snippet.starts_with("0x") || snippet.starts_with("0X")) {
return false;
}
@@ -1311,7 +1311,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// We have satisfied all requirements to provide a suggestion. Emit it.
err.span_suggestion(
- span,
+ *span,
format!("if you meant to create a null pointer, use `{null_path_str}()`"),
null_path_str + "()",
Applicability::MachineApplicable,
@@ -1384,7 +1384,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
let item_ty = self.tcx.type_of(item.def_id).subst_identity();
// FIXME(compiler-errors): This check is *so* rudimentary
- if item_ty.needs_subst() {
+ if item_ty.has_param() {
return false;
}
if self.can_coerce(item_ty, expected_ty) {
@@ -1438,7 +1438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&& !results.expr_adjustments(callee_expr).iter().any(|adj| matches!(adj.kind, ty::adjustment::Adjust::Deref(..)))
// Check that we're in fact trying to clone into the expected type
&& self.can_coerce(*pointee_ty, expected_ty)
- && let trait_ref = ty::Binder::dummy(self.tcx.mk_trait_ref(clone_trait_did, [expected_ty]))
+ && let trait_ref = ty::TraitRef::new(self.tcx, clone_trait_did, [expected_ty])
// And the expected type doesn't implement `Clone`
&& !self.predicate_must_hold_considering_regions(&traits::Obligation::new(
self.tcx,
@@ -1449,7 +1449,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
diag.span_note(
callee_expr.span,
- &format!(
+ format!(
"`{expected_ty}` does not implement `Clone`, so `{found_ty}` was cloned instead"
),
);
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
index 3e9a9ce1b..e4a62ec05 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_build.rs
@@ -8,7 +8,7 @@ use hir::{
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_infer::infer::InferCtxt;
use rustc_middle::{
hir::map::Map,
@@ -215,6 +215,7 @@ impl<'a, 'tcx> DropRangeVisitor<'a, 'tcx> {
| ExprKind::Continue(..)
| ExprKind::Ret(..)
| ExprKind::InlineAsm(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)
| ExprKind::Yield(..)
@@ -485,6 +486,7 @@ impl<'a, 'tcx> Visitor<'tcx> for DropRangeVisitor<'a, 'tcx> {
| ExprKind::Field(..)
| ExprKind::Index(..)
| ExprKind::InlineAsm(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::Let(..)
| ExprKind::Lit(..)
| ExprKind::Path(..)
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
index 139d17d2e..633b47889 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/cfg_propagate.rs
@@ -1,5 +1,5 @@
use super::{DropRangesBuilder, PostOrderId};
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use rustc_index::{bit_set::BitSet, IndexVec};
use std::collections::BTreeMap;
impl DropRangesBuilder {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
index f7b493bc2..ecafbd668 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/mod.rs
@@ -20,7 +20,7 @@ use hir::{Body, HirId, HirIdMap, Node};
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::hir::map::Map;
use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId};
use rustc_middle::ty;
@@ -193,7 +193,7 @@ impl DropRanges {
.get(&TrackedValue::Temporary(hir_id))
.or(self.tracked_value_map.get(&TrackedValue::Variable(hir_id)))
.cloned()
- .map_or(false, |tracked_value_id| {
+ .is_some_and(|tracked_value_id| {
self.expect_node(location.into()).drop_state.contains(tracked_value_id)
})
}
@@ -268,8 +268,7 @@ impl DropRangesBuilder {
fn node_mut(&mut self, id: PostOrderId) -> &mut NodeInfo {
let size = self.num_values();
- self.nodes.ensure_contains_elem(id, || NodeInfo::new(size));
- &mut self.nodes[id]
+ self.nodes.ensure_contains_elem(id, || NodeInfo::new(size))
}
fn add_control_edge(&mut self, from: PostOrderId, to: PostOrderId) {
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
index fa3887362..8ab0bd535 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/drop_ranges/record_consumed_borrow.rs
@@ -202,10 +202,10 @@ impl<'tcx> expr_use_visitor::Delegate<'tcx> for ExprUseDelegate<'tcx> {
// If the type being assigned needs dropped, then the mutation counts as a borrow
// since it is essentially doing `Drop::drop(&mut x); x = new_value;`.
let ty = self.tcx.erase_regions(assignee_place.place.base_ty);
- if ty.needs_infer() {
+ if ty.has_infer() {
self.tcx.sess.delay_span_bug(
self.tcx.hir().span(assignee_place.hir_id),
- &format!("inference variables in {ty}"),
+ format!("inference variables in {ty}"),
);
} else if ty.needs_drop(self.tcx, self.param_env) {
self.places
diff --git a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
index f39710804..019fb86f5 100644
--- a/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
+++ b/compiler/rustc_hir_typeck/src/generator_interior/mod.rs
@@ -112,7 +112,7 @@ impl<'a, 'tcx> InteriorVisitor<'a, 'tcx> {
self.fcx
.tcx
.sess
- .delay_span_bug(span, &format!("Encountered var {:?}", unresolved_term));
+ .delay_span_bug(span, format!("Encountered var {:?}", unresolved_term));
} else {
let note = format!(
"the type is part of the {} because of this {}",
@@ -460,11 +460,11 @@ impl<'a, 'tcx> Visitor<'tcx> for InteriorVisitor<'a, 'tcx> {
// Avoid ICEs in needs_drop.
let ty = self.fcx.resolve_vars_if_possible(ty);
let ty = self.fcx.tcx.erase_regions(ty);
- if ty.needs_infer() {
+ if ty.has_infer() {
self.fcx
.tcx
.sess
- .delay_span_bug(expr.span, &format!("inference variables in {ty}"));
+ .delay_span_bug(expr.span, format!("inference variables in {ty}"));
true
} else {
ty.needs_drop(self.fcx.tcx, self.fcx.param_env)
@@ -571,7 +571,7 @@ fn check_must_not_suspend_ty<'tcx>(
// FIXME: support adding the attribute to TAITs
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
- for &(predicate, _) in fcx.tcx.explicit_item_bounds(def) {
+ for &(predicate, _) in fcx.tcx.explicit_item_bounds(def).skip_binder() {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
predicate.kind().skip_binder()
@@ -650,7 +650,7 @@ fn check_must_not_suspend_ty<'tcx>(
},
)
}
- // If drop tracking is enabled, we want to look through references, since the referrent
+ // If drop tracking is enabled, we want to look through references, since the referent
// may not be considered live across the await point.
ty::Ref(_region, ty, _mutability) if fcx.sess().opts.unstable_opts.drop_tracking => {
let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs
index 4110b176b..294c3bb78 100644
--- a/compiler/rustc_hir_typeck/src/inherited.rs
+++ b/compiler/rustc_hir_typeck/src/inherited.rs
@@ -4,7 +4,8 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::HirIdMap;
-use rustc_infer::infer::{DefiningAnchor, InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt};
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_span::def_id::LocalDefIdMap;
@@ -130,7 +131,7 @@ impl<'tcx> Inherited<'tcx> {
// (*) binder skipped
if let ty::PredicateKind::Clause(ty::Clause::Trait(tpred)) = obligation.predicate.kind().skip_binder()
&& let Some(ty) = self.shallow_resolve(tpred.self_ty()).ty_vid().map(|t| self.root_var(t))
- && self.tcx.lang_items().sized_trait().map_or(false, |st| st != tpred.trait_ref.def_id)
+ && self.tcx.lang_items().sized_trait().is_some_and(|st| st != tpred.trait_ref.def_id)
{
let new_self_ty = self.tcx.types.unit;
diff --git a/compiler/rustc_hir_typeck/src/intrinsicck.rs b/compiler/rustc_hir_typeck/src/intrinsicck.rs
index 106f5bcd7..3c5eafd94 100644
--- a/compiler/rustc_hir_typeck/src/intrinsicck.rs
+++ b/compiler/rustc_hir_typeck/src/intrinsicck.rs
@@ -1,10 +1,10 @@
use hir::HirId;
use rustc_errors::struct_span_err;
use rustc_hir as hir;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::layout::{LayoutError, SizeSkeleton};
use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_target::abi::{FieldIdx, Pointer, VariantIdx};
+use rustc_target::abi::{Pointer, VariantIdx};
use super::FnCtxt;
@@ -28,7 +28,7 @@ fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
}
if def.variant(data_idx).fields.len() == 1 {
- return def.variant(data_idx).fields[FieldIdx::from_u32(0)].ty(tcx, substs);
+ return def.variant(data_idx).single_field().ty(tcx, substs);
}
}
@@ -72,8 +72,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let from = unpack_option_like(tcx, from);
if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) && size_to == Pointer(dl.instruction_address_space).size(&tcx) {
struct_span_err!(tcx.sess, span, E0591, "can't transmute zero-sized type")
- .note(&format!("source type: {from}"))
- .note(&format!("target type: {to}"))
+ .note(format!("source type: {from}"))
+ .note(format!("target type: {to}"))
.help("cast with `as` to a pointer instead")
.emit();
return;
@@ -109,10 +109,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
or dependently-sized types"
);
if from == to {
- err.note(&format!("`{from}` does not have a fixed size"));
+ err.note(format!("`{from}` does not have a fixed size"));
} else {
- err.note(&format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
- .note(&format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
+ err.note(format!("source type: `{}` ({})", from, skeleton_string(from, sk_from)))
+ .note(format!("target type: `{}` ({})", to, skeleton_string(to, sk_to)));
let mut should_delay_as_bug = false;
if let Err(LayoutError::Unknown(bad_from)) = sk_from && bad_from.references_error() {
should_delay_as_bug = true;
diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs
index 45890abad..b97b55d8f 100644
--- a/compiler/rustc_hir_typeck/src/lib.rs
+++ b/compiler/rustc_hir_typeck/src/lib.rs
@@ -2,6 +2,7 @@
#![feature(let_chains)]
#![feature(try_blocks)]
#![feature(never_type)]
+#![feature(box_patterns)]
#![feature(min_specialization)]
#![feature(control_flow_enum)]
#![feature(drain_filter)]
@@ -59,6 +60,7 @@ use rustc_errors::{
struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan,
SubdiagnosticMessage,
};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::intravisit::Visitor;
@@ -66,12 +68,10 @@ use rustc_hir::{HirIdMap, Node};
use rustc_hir_analysis::astconv::AstConv;
use rustc_hir_analysis::check::check_abi;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_macros::fluent_messages;
+use rustc_middle::query::Providers;
use rustc_middle::traits;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_session::config;
-use rustc_session::Session;
use rustc_span::def_id::{DefId, LocalDefId};
use rustc_span::{sym, Span};
@@ -152,25 +152,9 @@ fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &UnordSet<LocalDef
&*tcx.typeck(def_id).used_trait_imports
}
-fn typeck_item_bodies(tcx: TyCtxt<'_>, (): ()) {
- tcx.hir().par_body_owners(|body_owner_def_id| tcx.ensure().typeck(body_owner_def_id));
-}
-
-fn typeck_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- (did, param_did): (LocalDefId, DefId),
-) -> &ty::TypeckResults<'tcx> {
- let fallback = move || tcx.type_of(param_did).subst_identity();
- typeck_with_fallback(tcx, did, fallback)
-}
-
fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> {
- if let Some(param_did) = tcx.opt_const_param_of(def_id) {
- tcx.typeck_const_arg((def_id, param_did))
- } else {
- let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity();
- typeck_with_fallback(tcx, def_id, fallback)
- }
+ let fallback = move || tcx.type_of(def_id.to_def_id()).subst_identity();
+ typeck_with_fallback(tcx, def_id, fallback)
}
/// Used only to get `TypeckResults` for type inference during error recovery.
@@ -228,7 +212,7 @@ fn typeck_with_fallback<'tcx>(
let fn_sig = tcx.liberate_late_bound_regions(def_id.to_def_id(), fn_sig);
let fn_sig = fcx.normalize(body.value.span, fn_sig);
- check_fn(&mut fcx, fn_sig, decl, def_id, body, None);
+ check_fn(&mut fcx, fn_sig, decl, def_id, body, None, tcx.features().unsized_fn_params);
} else {
let expected_type = if let Some(&hir::Ty { kind: hir::TyKind::Infer, span, .. }) = body_ty {
Some(fcx.next_ty_var(TypeVariableOrigin {
@@ -237,12 +221,6 @@ fn typeck_with_fallback<'tcx>(
}))
} else if let Node::AnonConst(_) = node {
match tcx.hir().get(tcx.hir().parent_id(id)) {
- Node::Expr(&hir::Expr {
- kind: hir::ExprKind::ConstBlock(ref anon_const), ..
- }) if anon_const.hir_id == id => Some(fcx.next_ty_var(TypeVariableOrigin {
- kind: TypeVariableOriginKind::TypeInference,
- span,
- })),
Node::Ty(&hir::Ty { kind: hir::TyKind::Typeof(ref anon_const), .. })
if anon_const.hir_id == id =>
{
@@ -459,8 +437,8 @@ enum TupleArgumentsFlag {
TupleArguments,
}
-fn fatally_break_rust(sess: &Session) {
- let handler = sess.diagnostic();
+fn fatally_break_rust(tcx: TyCtxt<'_>) {
+ let handler = tcx.sess.diagnostic();
handler.span_bug_no_panic(
MultiSpan::new(),
"It looks like you're trying to break rust; would you like some ICE?",
@@ -470,29 +448,21 @@ fn fatally_break_rust(sess: &Session) {
"we would appreciate a joke overview: \
https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675",
);
- handler.note_without_error(&format!(
+ handler.note_without_error(format!(
"rustc {} running on {}",
- option_env!("CFG_VERSION").unwrap_or("unknown_version"),
+ tcx.sess.cfg_version,
config::host_triple(),
));
}
-fn has_expected_num_generic_args(
- tcx: TyCtxt<'_>,
- trait_did: Option<DefId>,
- expected: usize,
-) -> bool {
- trait_did.map_or(true, |trait_did| {
- let generics = tcx.generics_of(trait_did);
- generics.count() == expected + if generics.has_self { 1 } else { 0 }
- })
+fn has_expected_num_generic_args(tcx: TyCtxt<'_>, trait_did: DefId, expected: usize) -> bool {
+ let generics = tcx.generics_of(trait_did);
+ generics.count() == expected + if generics.has_self { 1 } else { 0 }
}
pub fn provide(providers: &mut Providers) {
method::provide(providers);
*providers = Providers {
- typeck_item_bodies,
- typeck_const_arg,
typeck,
diagnostic_only_typeck,
has_typeck_results,
diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs
index 6c861b593..78171e0b2 100644
--- a/compiler/rustc_hir_typeck/src/mem_categorization.rs
+++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs
@@ -381,6 +381,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Err(_) => Ok(self.cat_rvalue(expr.hir_id, expr.span, expr_ty)),
}
}
@@ -410,7 +411,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> {
}
Res::Local(var_id) => {
- if self.upvars.map_or(false, |upvars| upvars.contains_key(&var_id)) {
+ if self.upvars.is_some_and(|upvars| upvars.contains_key(&var_id)) {
self.cat_upvar(hir_id, var_id)
} else {
Ok(PlaceWithHirId::new(hir_id, expr_ty, PlaceBase::Local(var_id), Vec::new()))
diff --git a/compiler/rustc_hir_typeck/src/method/confirm.rs b/compiler/rustc_hir_typeck/src/method/confirm.rs
index 9155a3d8d..98529b666 100644
--- a/compiler/rustc_hir_typeck/src/method/confirm.rs
+++ b/compiler/rustc_hir_typeck/src/method/confirm.rs
@@ -158,7 +158,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
let Some((ty, n)) = autoderef.nth(pick.autoderefs) else {
return self.tcx.ty_error_with_message(
rustc_span::DUMMY_SP,
- &format!("failed autoderef {}", pick.autoderefs),
+ format!("failed autoderef {}", pick.autoderefs),
);
};
assert_eq!(n, pick.autoderefs);
@@ -471,7 +471,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
self_ty, method_self_ty, self.span, pick
);
let cause = self.cause(
- self.span,
+ self.self_expr.span,
ObligationCauseCode::UnifyReceiver(Box::new(UnifyReceiverContext {
assoc_item: pick.item,
param_env: self.param_env,
@@ -482,13 +482,22 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> {
Ok(InferOk { obligations, value: () }) => {
self.register_predicates(obligations);
}
- Err(_) => {
- span_bug!(
- self.span,
- "{} was a subtype of {} but now is not?",
- self_ty,
- method_self_ty
- );
+ Err(terr) => {
+ // FIXME(arbitrary_self_types): We probably should limit the
+ // situations where this can occur by adding additional restrictions
+ // to the feature, like the self type can't reference method substs.
+ if self.tcx.features().arbitrary_self_types {
+ self.err_ctxt()
+ .report_mismatched_types(&cause, method_self_ty, self_ty, terr)
+ .emit();
+ } else {
+ span_bug!(
+ self.span,
+ "{} was a subtype of {} but now is not?",
+ self_ty,
+ method_self_ty
+ );
+ }
}
}
}
diff --git a/compiler/rustc_hir_typeck/src/method/mod.rs b/compiler/rustc_hir_typeck/src/method/mod.rs
index 0456dd56c..6f4d674ba 100644
--- a/compiler/rustc_hir_typeck/src/method/mod.rs
+++ b/compiler/rustc_hir_typeck/src/method/mod.rs
@@ -13,11 +13,12 @@ pub use self::MethodError::*;
use crate::errors::OpMethodGenericParams;
use crate::FnCtxt;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, Diagnostic};
+use rustc_errors::{Applicability, Diagnostic, SubdiagnosticMessage};
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Namespace};
use rustc_hir::def_id::DefId;
use rustc_infer::infer::{self, InferOk};
+use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::subst::{InternalSubsts, SubstsRef};
use rustc_middle::ty::{self, GenericParamDefKind, Ty, TypeVisitableExt};
@@ -28,7 +29,7 @@ use rustc_trait_selection::traits::{self, NormalizeExt};
use self::probe::{IsSuggestion, ProbeScope};
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
probe::provide(providers);
}
@@ -129,7 +130,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pub(crate) fn suggest_method_call(
&self,
err: &mut Diagnostic,
- msg: &str,
+ msg: impl Into<SubdiagnosticMessage> + std::fmt::Debug,
method_name: Ident,
self_ty: Ty<'tcx>,
call_expr: &hir::Expr<'tcx>,
@@ -300,8 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
trait_def_id: DefId,
self_ty: Ty<'tcx>,
opt_input_types: Option<&[Ty<'tcx>]>,
- ) -> (traits::Obligation<'tcx, ty::Predicate<'tcx>>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>)
- {
+ ) -> (traits::PredicateObligation<'tcx>, &'tcx ty::List<ty::subst::GenericArg<'tcx>>) {
// Construct a trait-reference `self_ty : Trait<input_tys>`
let substs = InternalSubsts::for_item(self.tcx, trait_def_id, |param, _| {
match param.kind {
@@ -317,7 +317,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.var_for_def(cause.span, param)
});
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, substs);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, substs);
// Construct an obligation
let poly_trait_ref = ty::Binder::dummy(trait_ref);
diff --git a/compiler/rustc_hir_typeck/src/method/prelude2021.rs b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
index 3d6c2119b..ec4e7f7f8 100644
--- a/compiler/rustc_hir_typeck/src/method/prelude2021.rs
+++ b/compiler/rustc_hir_typeck/src/method/prelude2021.rs
@@ -118,7 +118,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
lint.span_help(
sp,
- &format!("disambiguate the method call with `({})`", self_adjusted,),
+ format!("disambiguate the method call with `({})`", self_adjusted,),
);
}
@@ -180,7 +180,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
lint.span_help(
sp,
- &format!(
+ format!(
"disambiguate the associated function with `{}::{}(...)`",
trait_name, segment.ident,
),
diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs
index 4fd778910..9f3d35a77 100644
--- a/compiler/rustc_hir_typeck/src/method/probe.rs
+++ b/compiler/rustc_hir_typeck/src/method/probe.rs
@@ -3,7 +3,7 @@ use super::CandidateSource;
use super::MethodError;
use super::NoMatchData;
-use crate::errors::MethodCallOnUnknownType;
+use crate::errors::MethodCallOnUnknownRawPointee;
use crate::FnCtxt;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::Applicability;
@@ -16,6 +16,7 @@ use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::DefineOpaqueTypes;
use rustc_infer::infer::{self, InferOk, TyCtxtInferExt};
use rustc_middle::middle::stability;
+use rustc_middle::query::Providers;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::AssocItem;
use rustc_middle::ty::GenericParamDefKind;
@@ -437,7 +438,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// so we do a future-compat lint here for the 2015 edition
// (see https://github.com/rust-lang/rust/issues/46906)
if self.tcx.sess.rust_2018() {
- self.tcx.sess.emit_err(MethodCallOnUnknownType { span });
+ self.tcx.sess.emit_err(MethodCallOnUnknownRawPointee { span });
} else {
self.tcx.struct_span_lint_hir(
lint::builtin::TYVAR_BEHIND_RAW_POINTER,
@@ -495,7 +496,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
providers.method_autoderef_steps = method_autoderef_steps;
}
@@ -954,7 +955,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
) {
debug!("assemble_extension_candidates_for_trait(trait_def_id={:?})", trait_def_id);
let trait_substs = self.fresh_item_substs(trait_def_id);
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, trait_substs);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, trait_substs);
if self.tcx.is_trait_alias(trait_def_id) {
// For trait aliases, recursively assume all explicitly named traits are relevant
@@ -1193,7 +1194,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> {
pick.autoderefs += 1;
pick.autoref_or_ptr_adjustment = Some(AutorefOrPtrAdjustment::Autoref {
mutbl,
- unsize: pick.autoref_or_ptr_adjustment.map_or(false, |a| a.get_unsize()),
+ unsize: pick.autoref_or_ptr_adjustment.is_some_and(|a| a.get_unsize()),
})
}
@@ -1396,7 +1397,7 @@ impl<'tcx> Pick<'tcx> {
// However `self.span` only
// highlights the method name, so we can't use it. Also consider reusing
// the code from `report_method_error()`.
- lint.help(&format!(
+ lint.help(format!(
"call with fully qualified syntax `{}(...)` to keep using the current \
method",
tcx.def_path_str(self.item.def_id),
@@ -1420,7 +1421,7 @@ impl<'tcx> Pick<'tcx> {
}
if tcx.sess.is_nightly_build() {
for (candidate, feature) in &self.unstable_candidates {
- lint.help(&format!(
+ lint.help(format!(
"add `#![feature({})]` to the crate attributes to enable `{}`",
feature,
tcx.def_path_str(candidate.item.def_id),
@@ -2032,7 +2033,7 @@ impl<'tcx> Candidate<'tcx> {
// means they are safe to put into the
// `WhereClausePick`.
assert!(
- !trait_ref.skip_binder().substs.needs_infer()
+ !trait_ref.skip_binder().substs.has_infer()
&& !trait_ref.skip_binder().substs.has_placeholders()
);
diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs
index 900a6fa0d..e04cc44b5 100644
--- a/compiler/rustc_hir_typeck/src/method/suggest.rs
+++ b/compiler/rustc_hir_typeck/src/method/suggest.rs
@@ -2,6 +2,8 @@
//! found or is otherwise invalid.
use crate::errors;
+use crate::errors::CandidateTraitNote;
+use crate::errors::NoAssociatedItem;
use crate::Expectation;
use crate::FnCtxt;
use rustc_ast::ast::Mutability;
@@ -27,8 +29,8 @@ use rustc_middle::traits::util::supertraits;
use rustc_middle::ty::fast_reject::DeepRejectCtxt;
use rustc_middle::ty::fast_reject::{simplify_type, TreatParams};
use rustc_middle::ty::print::{with_crate_prefix, with_forced_trimmed_paths};
+use rustc_middle::ty::IsSuggestable;
use rustc_middle::ty::{self, GenericArgKind, Ty, TyCtxt, TypeVisitableExt};
-use rustc_middle::ty::{IsSuggestable, ToPolyTraitRef};
use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use rustc_span::{edit_distance, source_map, ExpnKind, FileName, MacroKind, Span};
@@ -38,6 +40,7 @@ use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _
use rustc_trait_selection::traits::{
FulfillmentError, Obligation, ObligationCause, ObligationCauseCode,
};
+use std::borrow::Cow;
use super::probe::{AutorefOrPtrAdjustment, IsSuggestion, Mode, ProbeScope};
use super::{CandidateSource, MethodError, NoMatchData};
@@ -72,7 +75,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.autoderef(span, ty).any(|(ty, _)| {
info!("check deref {:?} impl FnOnce", ty);
self.probe(|_| {
- let trait_ref = tcx.mk_trait_ref(
+ let trait_ref = ty::TraitRef::new(
+ tcx,
fn_once,
[
ty,
@@ -111,6 +115,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
error: MethodError<'tcx>,
args: Option<(&'tcx hir::Expr<'tcx>, &'tcx [hir::Expr<'tcx>])>,
expected: Expectation<'tcx>,
+ trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
// Avoid suggestions when we don't know what's going on.
if rcvr_ty.references_error() {
@@ -135,6 +140,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg_span,
&mut no_match_data,
expected,
+ trait_missing_method,
);
}
@@ -169,13 +175,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind,
item_name
);
- err.span_label(item_name.span, &format!("private {}", kind));
+ err.span_label(item_name.span, format!("private {}", kind));
let sp = self
.tcx
.hir()
.span_if_local(def_id)
.unwrap_or_else(|| self.tcx.def_span(def_id));
- err.span_label(sp, &format!("private {} defined here", kind));
+ err.span_label(sp, format!("private {} defined here", kind));
self.suggest_valid_traits(&mut err, out_of_scope_traits);
err.emit();
}
@@ -188,7 +194,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
format!("the `{item_name}` method cannot be invoked on a trait object")
};
- let mut err = self.sess().struct_span_err(span, &msg);
+ let mut err = self.sess().struct_span_err(span, msg);
if !needs_mut {
err.span_label(bound_span, "this has a `Sized` requirement");
}
@@ -228,12 +234,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.span_suggestion_verbose(
mut_ty.ty.span.shrink_to_lo(),
- &msg,
+ msg,
"mut ",
Applicability::MachineApplicable,
);
} else {
- err.help(&msg);
+ err.help(msg);
}
}
}
@@ -277,12 +283,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sugg_span: Span,
no_match_data: &mut NoMatchData<'tcx>,
expected: Expectation<'tcx>,
+ trait_missing_method: bool,
) -> Option<DiagnosticBuilder<'_, ErrorGuaranteed>> {
let mode = no_match_data.mode;
let tcx = self.tcx;
let rcvr_ty = self.resolve_vars_if_possible(rcvr_ty);
- let (ty_str, ty_file) = tcx.short_ty_string(rcvr_ty);
- let short_ty_str = with_forced_trimmed_paths!(rcvr_ty.to_string());
+ let ((mut ty_str, ty_file), short_ty_str) = if trait_missing_method
+ && let ty::Dynamic(predicates, _, _) = rcvr_ty.kind() {
+ ((predicates.to_string(), None), with_forced_trimmed_paths!(predicates.to_string()))
+ } else {
+ (tcx.short_ty_string(rcvr_ty), with_forced_trimmed_paths!(rcvr_ty.to_string()))
+ };
let is_method = mode == Mode::MethodCall;
let unsatisfied_predicates = &no_match_data.unsatisfied_predicates;
let similar_candidate = no_match_data.similar_candidate;
@@ -345,7 +356,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.map_or(false, |def_id| {
+ let is_write = sugg_span.ctxt().outer_expn_data().macro_def_id.is_some_and(|def_id| {
tcx.is_diagnostic_item(sym::write_macro, def_id)
|| tcx.is_diagnostic_item(sym::writeln_macro, def_id)
}) && item_name.name == Symbol::intern("write_fmt");
@@ -354,34 +365,37 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
self.suggest_missing_writer(rcvr_ty, args)
} else {
- struct_span_err!(
- tcx.sess,
+ tcx.sess.create_err(NoAssociatedItem {
span,
- E0599,
- "no {} named `{}` found for {} `{}` in the current scope",
item_kind,
item_name,
- rcvr_ty.prefix_string(self.tcx),
- ty_str_reported,
- )
+ ty_prefix: if trait_missing_method {
+ // FIXME(mu001999) E0599 maybe not suitable here because it is for types
+ Cow::from("trait")
+ } else {
+ rcvr_ty.prefix_string(self.tcx)
+ },
+ ty_str: ty_str_reported,
+ trait_missing_method,
+ })
};
if tcx.sess.source_map().is_multiline(sugg_span) {
err.span_label(sugg_span.with_hi(span.lo()), "");
}
- let ty_str = if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
- short_ty_str
- } else {
- ty_str
- };
+
+ if short_ty_str.len() < ty_str.len() && ty_str.len() > 10 {
+ ty_str = short_ty_str;
+ }
+
if let Some(file) = ty_file {
- err.note(&format!("the full type name has been written to '{}'", file.display(),));
+ err.note(format!("the full type name has been written to '{}'", file.display(),));
}
if rcvr_ty.references_error() {
err.downgrade_to_delayed_bug();
}
if tcx.ty_is_opaque_future(rcvr_ty) && item_name.name == sym::poll {
- err.help(&format!(
+ err.help(format!(
"method `poll` found on `Pin<&mut {ty_str}>`, \
see documentation for `std::pin::Pin`"
));
@@ -510,7 +524,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
if let Some(iterator_trait) = self.tcx.get_diagnostic_item(sym::Iterator) {
let iterator_trait = self.tcx.def_path_str(iterator_trait);
- err.note(&format!(
+ err.note(format!(
"`count` is defined on `{iterator_trait}`, which `{rcvr_ty}` does not implement"
));
}
@@ -810,7 +824,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for (sp, label) in span_labels {
span.push_span_label(sp, label);
}
- err.span_note(span, &msg);
+ err.span_note(span, msg);
unsatisfied_bounds = true;
}
@@ -867,7 +881,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
obligations.sort();
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"consider restricting the type parameter{s} to satisfy the \
trait bound{s}",
s = pluralize!(obligations.len())
@@ -912,13 +926,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
but its trait bounds were not satisfied"
)
});
- err.set_primary_message(&primary_message);
+ err.set_primary_message(primary_message);
if let Some(label) = label {
custom_span_label = true;
err.span_label(span, label);
}
if !bound_list.is_empty() {
- err.note(&format!(
+ err.note(format!(
"the following trait bounds were not satisfied:\n{bound_list}"
));
}
@@ -1002,7 +1016,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
"".to_string()
};
- err.note(&format!(
+ err.note(format!(
"the {item_kind} was found for\n{}{}",
type_candidates, additional_types
));
@@ -1044,12 +1058,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
}
- self.check_for_inner_self(&mut err, source, rcvr_ty, item_name);
+ self.suggest_unwrapping_inner_self(&mut err, source, rcvr_ty, item_name);
bound_spans.sort();
bound_spans.dedup();
for (span, msg) in bound_spans.into_iter() {
- err.span_label(span, &msg);
+ err.span_label(span, msg);
}
if rcvr_ty.is_numeric() && rcvr_ty.is_fresh() || restrict_type_params {
@@ -1066,6 +1080,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
&static_candidates,
unsatisfied_bounds,
expected.only_has_type(self),
+ trait_missing_method,
);
}
@@ -1119,7 +1134,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
err.span_suggestion(
span,
- &format!(
+ format!(
"there is {} {} with a similar name",
self.tcx.def_kind_descr_article(def_kind, similar_candidate.def_id),
self.tcx.def_kind_descr(def_kind, similar_candidate.def_id)
@@ -1131,7 +1146,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- self.check_for_deref_method(&mut err, source, rcvr_ty, item_name, expected);
+ self.note_derefed_ty_has_method(&mut err, source, rcvr_ty, item_name, expected);
return Some(err);
}
@@ -1203,9 +1218,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
if let Some(note_span) = note_span {
// We have a span pointing to the method. Show note with snippet.
- err.span_note(note_span, &note_str);
+ err.span_note(note_span, note_str);
} else {
- err.note(&note_str);
+ err.note(note_str);
}
if let Some(sugg_span) = sugg_span
&& let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
@@ -1243,7 +1258,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let Some(item) = self.associated_value(trait_did, item_name) else { continue };
let item_span = self.tcx.def_span(item.def_id);
let idx = if sources.len() > 1 {
- let msg = &format!(
+ let msg = format!(
"candidate #{} is defined in the trait `{}`",
idx + 1,
self.tcx.def_path_str(trait_did)
@@ -1251,7 +1266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(item_span, msg);
Some(idx + 1)
} else {
- let msg = &format!(
+ let msg = format!(
"the candidate is defined in the trait `{}`",
self.tcx.def_path_str(trait_did)
);
@@ -1278,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
if sources.len() > limit {
- err.note(&format!("and {} others", sources.len() - limit));
+ err.note(format!("and {} others", sources.len() - limit));
}
}
@@ -1402,7 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
applicability,
);
} else {
- err.help(&format!("try with `{}::{}`", ty_str, item_name,));
+ err.help(format!("try with `{}::{}`", ty_str, item_name,));
}
}
@@ -1436,7 +1451,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if self.is_fn_ty(field_ty, span) {
let expr_span = expr.span.to(item_name.span);
err.multipart_suggestion(
- &format!(
+ format!(
"to call the function stored in `{}`, \
surround the field access with parentheses",
item_name,
@@ -1507,7 +1522,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span_included = match parent_expr.kind {
hir::ExprKind::Struct(_, eps, _) => {
- eps.len() > 0 && eps.last().map_or(false, |ep| ep.span.contains(span))
+ eps.len() > 0 && eps.last().is_some_and(|ep| ep.span.contains(span))
}
// `..=` desugars into `::std::ops::RangeInclusive::new(...)`.
hir::ExprKind::Call(ref func, ..) => func.span.contains(span),
@@ -1530,7 +1545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
if pick.is_ok() {
let range_span = parent_expr.span.with_hi(expr.span.hi());
- tcx.sess.emit_err(errors::MissingParentheseInRange {
+ tcx.sess.emit_err(errors::MissingParenthesesInRange {
span,
ty_str: ty_str.to_string(),
method_name: item_name.as_str().to_string(),
@@ -1612,7 +1627,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let snippet = snippet.strip_suffix('.').unwrap_or(&snippet);
err.span_suggestion(
lit.span,
- &format!(
+ format!(
"you must specify a concrete type for this numeric value, \
like `{}`",
concrete_type
@@ -1648,7 +1663,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// account for `let x: _ = 42;`
// ^^^
type_span,
- &msg,
+ msg,
format!(": {concrete_type}"),
Applicability::MaybeIncorrect,
);
@@ -1766,7 +1781,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
ProbeScope::TraitsInScope,
return_type,
)
- .map_or(false, |pick| {
+ .is_ok_and(|pick| {
!never_mention_traits
.iter()
.flatten()
@@ -1804,7 +1819,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
}
- fn check_for_inner_self(
+ fn suggest_unwrapping_inner_self(
&self,
err: &mut Diagnostic,
source: SelfSource<'tcx>,
@@ -1861,7 +1876,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let self_ty = field.ty(tcx, substs);
err.span_note(
tcx.def_span(pick.item.def_id),
- &format!("the method `{item_name}` exists on the type `{self_ty}`"),
+ format!("the method `{item_name}` exists on the type `{self_ty}`"),
);
let (article, kind, variant, question) =
if tcx.is_diagnostic_item(sym::Result, kind.did()) {
@@ -1975,7 +1990,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_note(
tcx.def_span(pick.item.def_id),
- &format!("the method `{item_name}` exists on the type `{ty}`"),
+ format!("the method `{item_name}` exists on the type `{ty}`"),
);
}
}
@@ -2046,7 +2061,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
pluralize!(preds.len()),
)
};
- err.span_note(spans, &msg);
+ err.span_note(spans, msg);
}
let preds: Vec<_> = errors
@@ -2068,7 +2083,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut derives = Vec::<(String, Span, Symbol)>::new();
let mut traits = Vec::new();
for (pred, _, _) in unsatisfied_predicates {
- let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = pred.kind().skip_binder() else { continue };
+ let Some(ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred))) =
+ pred.kind().no_bound_vars()
+ else {
+ continue
+ };
let adt = match trait_pred.self_ty().ty_adt_def() {
Some(adt) if adt.did().is_local() => adt,
_ => continue,
@@ -2089,18 +2108,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if can_derive {
let self_name = trait_pred.self_ty().to_string();
let self_span = self.tcx.def_span(adt.did());
- if let Some(poly_trait_ref) = pred.to_opt_poly_trait_pred() {
- for super_trait in supertraits(self.tcx, poly_trait_ref.to_poly_trait_ref())
+ for super_trait in
+ supertraits(self.tcx, ty::Binder::dummy(trait_pred.trait_ref))
+ {
+ if let Some(parent_diagnostic_name) =
+ self.tcx.get_diagnostic_name(super_trait.def_id())
{
- if let Some(parent_diagnostic_name) =
- self.tcx.get_diagnostic_name(super_trait.def_id())
- {
- derives.push((
- self_name.clone(),
- self_span,
- parent_diagnostic_name,
- ));
- }
+ derives.push((self_name.clone(), self_span, parent_diagnostic_name));
}
}
derives.push((self_name, self_span, diagnostic_name));
@@ -2147,21 +2161,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.span_note(
span,
- &format!("the trait{} {} must be implemented", pluralize!(len), names),
+ format!("the trait{} {} must be implemented", pluralize!(len), names),
);
}
for (self_name, self_span, traits) in &derives_grouped {
err.span_suggestion_verbose(
self_span.shrink_to_lo(),
- &format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
+ format!("consider annotating `{}` with `#[derive({})]`", self_name, traits),
format!("#[derive({})]\n", traits),
Applicability::MaybeIncorrect,
);
}
}
- fn check_for_deref_method(
+ fn note_derefed_ty_has_method(
&self,
err: &mut Diagnostic,
self_source: SelfSource<'tcx>,
@@ -2197,7 +2211,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
| ty::Float(_)
| ty::Adt(_, _)
| ty::Str
- | ty::Alias(ty::Projection, _)
+ | ty::Alias(ty::Projection | ty::Inherent, _)
| ty::Param(_) => format!("{deref_ty}"),
// we need to test something like <&[_]>::len or <(&[u32])>::len
// and Vec::function();
@@ -2300,7 +2314,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
err.span_suggestions(
span,
- &msg,
+ msg,
path_strings.chain(glob_path_strings),
Applicability::MaybeIncorrect,
);
@@ -2332,7 +2346,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.suggest_use_candidates(err, msg, candidates);
if let Some(did) = edition_fix {
- err.note(&format!(
+ err.note(format!(
"'{}' is included in the prelude starting in Edition 2021",
with_crate_prefix!(self.tcx.def_path_str(did))
));
@@ -2361,6 +2375,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
static_candidates: &[CandidateSource],
unsatisfied_bounds: bool,
return_type: Option<Ty<'tcx>>,
+ trait_missing_method: bool,
) {
let mut alt_rcvr_sugg = false;
if let (SelfSource::MethodCall(rcvr), false) = (source, unsatisfied_bounds) {
@@ -2400,7 +2415,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- &format!("the method is available for `{}` here", rcvr_ty),
+ format!("the method is available for `{}` here", rcvr_ty),
);
}
break;
@@ -2439,14 +2454,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// implement the `AsRef` trait.
let skip = skippable.contains(&did)
|| (("Pin::new" == *pre) && (sym::as_ref == item_name.name))
- || inputs_len.map_or(false, |inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
+ || inputs_len.is_some_and(|inputs_len| pick.item.kind == ty::AssocKind::Fn && self.tcx.fn_sig(pick.item.def_id).skip_binder().skip_binder().inputs().len() != inputs_len);
// Make sure the method is defined for the *actual* receiver: we don't
// want to treat `Box<Self>` as a receiver if it only works because of
// an autoderef to `&self`
if pick.autoderefs == 0 && !skip {
err.span_label(
pick.item.ident(self.tcx).span,
- &format!("the method is available for `{}` here", new_rcvr_t),
+ format!("the method is available for `{}` here", new_rcvr_t),
);
err.multipart_suggestion(
"consider wrapping the receiver expression with the \
@@ -2584,11 +2599,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
_ => None,
};
- err.help(if param_type.is_some() {
- "items from traits can only be used if the type parameter is bounded by the trait"
- } else {
- "items from traits can only be used if the trait is implemented and in scope"
- });
+ if !trait_missing_method {
+ err.help(if param_type.is_some() {
+ "items from traits can only be used if the type parameter is bounded by the trait"
+ } else {
+ "items from traits can only be used if the trait is implemented and in scope"
+ });
+ }
+
let candidates_len = candidates.len();
let message = |action| {
format!(
@@ -2619,47 +2637,62 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Nothing,
}
let ast_generics = hir.get_generics(id.owner.def_id).unwrap();
- let (sp, mut introducer) = if let Some(span) =
- ast_generics.bounds_span_for_suggestions(def_id)
- {
- (span, Introducer::Plus)
- } else if let Some(colon_span) = param.colon_span {
- (colon_span.shrink_to_hi(), Introducer::Nothing)
- } else {
- (param.span.shrink_to_hi(), Introducer::Colon)
- };
- if matches!(
- param.kind,
- hir::GenericParamKind::Type { synthetic: true, .. },
- ) {
- introducer = Introducer::Plus
- }
let trait_def_ids: FxHashSet<DefId> = ast_generics
.bounds_for_param(def_id)
.flat_map(|bp| bp.bounds.iter())
.filter_map(|bound| bound.trait_ref()?.trait_def_id())
.collect();
- if !candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
- err.span_suggestions(
- sp,
- &message(format!(
- "restrict type parameter `{}` with",
- param.name.ident(),
- )),
+ if candidates.iter().any(|t| trait_def_ids.contains(&t.def_id)) {
+ return;
+ }
+ let msg = message(format!(
+ "restrict type parameter `{}` with",
+ param.name.ident(),
+ ));
+ let bounds_span = ast_generics.bounds_span_for_suggestions(def_id);
+ if rcvr_ty.is_ref() && param.is_impl_trait() && bounds_span.is_some() {
+ err.multipart_suggestions(
+ msg,
candidates.iter().map(|t| {
- format!(
- "{} {}",
- match introducer {
- Introducer::Plus => " +",
- Introducer::Colon => ":",
- Introducer::Nothing => "",
- },
- self.tcx.def_path_str(t.def_id),
- )
+ vec![
+ (param.span.shrink_to_lo(), "(".to_string()),
+ (
+ bounds_span.unwrap(),
+ format!(" + {})", self.tcx.def_path_str(t.def_id)),
+ ),
+ ]
}),
Applicability::MaybeIncorrect,
);
+ return;
}
+
+ let (sp, introducer) = if let Some(span) = bounds_span {
+ (span, Introducer::Plus)
+ } else if let Some(colon_span) = param.colon_span {
+ (colon_span.shrink_to_hi(), Introducer::Nothing)
+ } else if param.is_impl_trait() {
+ (param.span.shrink_to_hi(), Introducer::Plus)
+ } else {
+ (param.span.shrink_to_hi(), Introducer::Colon)
+ };
+
+ err.span_suggestions(
+ sp,
+ msg,
+ candidates.iter().map(|t| {
+ format!(
+ "{} {}",
+ match introducer {
+ Introducer::Plus => " +",
+ Introducer::Colon => ":",
+ Introducer::Nothing => "",
+ },
+ self.tcx.def_path_str(t.def_id)
+ )
+ }),
+ Applicability::MaybeIncorrect,
+ );
return;
}
Node::Item(hir::Item {
@@ -2674,7 +2707,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
err.span_suggestions(
sp,
- &message(format!("add {} supertrait for", article)),
+ message(format!("add {} supertrait for", article)),
candidates.iter().map(|t| {
format!("{} {}", sep, self.tcx.def_path_str(t.def_id),)
}),
@@ -2708,7 +2741,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let imp = self.tcx.impl_trait_ref(imp_did).unwrap().subst_identity();
let imp_simp =
simplify_type(self.tcx, imp.self_ty(), TreatParams::ForLookup);
- imp_simp.map_or(false, |s| s == simp_rcvr_ty)
+ imp_simp.is_some_and(|s| s == simp_rcvr_ty)
})
{
explicitly_negative.push(candidate);
@@ -2722,27 +2755,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
(candidates, Vec::new())
};
- let action = if let Some(param) = param_type {
- format!("restrict type parameter `{}` with", param)
- } else {
- // FIXME: it might only need to be imported into scope, not implemented.
- "implement".to_string()
- };
match &potential_candidates[..] {
[] => {}
[trait_info] if trait_info.def_id.is_local() => {
- err.span_note(
- self.tcx.def_span(trait_info.def_id),
- &format!(
- "`{}` defines an item `{}`, perhaps you need to {} it",
- self.tcx.def_path_str(trait_info.def_id),
- item_name,
- action
- ),
- );
+ err.subdiagnostic(CandidateTraitNote {
+ span: self.tcx.def_span(trait_info.def_id),
+ trait_name: self.tcx.def_path_str(trait_info.def_id),
+ item_name,
+ action_or_ty: if trait_missing_method {
+ "NONE".to_string()
+ } else {
+ param_type.map_or_else(
+ || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
+ ToString::to_string,
+ )
+ },
+ });
}
trait_infos => {
- let mut msg = message(action);
+ let mut msg = message(param_type.map_or_else(
+ || "implement".to_string(), // FIXME: it might only need to be imported into scope, not implemented.
+ |param| format!("restrict type parameter `{}` with", param),
+ ));
for (i, trait_info) in trait_infos.iter().enumerate() {
msg.push_str(&format!(
"\ncandidate #{}: `{}`",
@@ -2750,7 +2784,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.def_path_str(trait_info.def_id),
));
}
- err.note(&msg);
+ err.note(msg);
}
}
match &explicitly_negative[..] {
@@ -2761,7 +2795,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.def_path_str(trait_info.def_id),
item_name
);
- err.note(&msg);
+ err.note(msg);
}
trait_infos => {
let mut msg = format!(
@@ -2771,7 +2805,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
for trait_info in trait_infos {
msg.push_str(&format!("\n{}", self.tcx.def_path_str(trait_info.def_id)));
}
- err.note(&msg);
+ err.note(msg);
}
}
}
@@ -2823,7 +2857,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn_args.len() == args.len() + 1 {
err.span_suggestion_verbose(
method_name.span.shrink_to_hi(),
- &format!("try calling `{}` instead", new_name.name.as_str()),
+ format!("try calling `{}` instead", new_name.name.as_str()),
"_else",
Applicability::MaybeIncorrect,
);
@@ -2845,7 +2879,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
match ty.kind() {
ty::Adt(def, _) => def.did().is_local(),
ty::Foreign(did) => did.is_local(),
- ty::Dynamic(tr, ..) => tr.principal().map_or(false, |d| d.def_id().is_local()),
+ ty::Dynamic(tr, ..) => tr.principal().is_some_and(|d| d.def_id().is_local()),
ty::Param(_) => true,
// Everything else (primitive types, etc.) is effectively
@@ -2943,7 +2977,7 @@ fn print_disambiguation_help<'tcx>(
};
err.span_suggestion_verbose(
span,
- &format!(
+ format!(
"disambiguate the {} for {}",
def_kind_descr,
if let Some(candidate) = candidate {
diff --git a/compiler/rustc_hir_typeck/src/op.rs b/compiler/rustc_hir_typeck/src/op.rs
index a52c94cb0..b8bf2b691 100644
--- a/compiler/rustc_hir_typeck/src/op.rs
+++ b/compiler/rustc_hir_typeck/src/op.rs
@@ -390,7 +390,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
.is_ok()
{
- let msg = &format!(
+ let msg = format!(
"`{}{}` can be used on `{}` if you dereference the left-hand side",
op.node.as_str(),
match is_assign {
@@ -408,7 +408,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
};
- let is_compatible = |lhs_ty, rhs_ty| {
+ let is_compatible_after_call = |lhs_ty, rhs_ty| {
self.lookup_op_method(
lhs_ty,
Some((rhs_expr, rhs_ty)),
@@ -416,6 +416,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
expected,
)
.is_ok()
+ // Suggest calling even if, after calling, the types don't
+ // implement the operator, since it'll lead to better
+ // diagnostics later.
+ || self.can_eq(self.param_env, lhs_ty, rhs_ty)
};
// We should suggest `a + b` => `*a + b` if `a` is copy, and suggest
@@ -436,16 +440,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
suggest_deref_binop(*lhs_deref_ty);
}
} else if self.suggest_fn_call(&mut err, lhs_expr, lhs_ty, |lhs_ty| {
- is_compatible(lhs_ty, rhs_ty)
+ is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_fn_call(&mut err, rhs_expr, rhs_ty, |rhs_ty| {
- is_compatible(lhs_ty, rhs_ty)
+ is_compatible_after_call(lhs_ty, rhs_ty)
}) || self.suggest_two_fn_call(
&mut err,
rhs_expr,
rhs_ty,
lhs_expr,
lhs_ty,
- |lhs_ty, rhs_ty| is_compatible(lhs_ty, rhs_ty),
+ |lhs_ty, rhs_ty| is_compatible_after_call(lhs_ty, rhs_ty),
) {
// Cool
}
@@ -511,7 +515,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
// When we know that a missing bound is responsible, we don't show
// this note as it is redundant.
- err.note(&format!(
+ err.note(format!(
"the trait `{missing_trait}` is not implemented for `{lhs_ty}`"
));
}
@@ -545,9 +549,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let to_owned_msg = "create an owned `String` from a string reference";
let string_type = self.tcx.lang_items().string();
- let is_std_string = |ty: Ty<'tcx>| {
- ty.ty_adt_def().map_or(false, |ty_def| Some(ty_def.did()) == string_type)
- };
+ let is_std_string =
+ |ty: Ty<'tcx>| ty.ty_adt_def().is_some_and(|ty_def| Some(ty_def.did()) == string_type);
match (lhs_ty.kind(), rhs_ty.kind()) {
(&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str
@@ -686,7 +689,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
{
err.span_suggestion(
ex.span,
- &format!(
+ format!(
"you may have meant the maximum value of `{actual}`",
),
format!("{actual}::MAX"),
@@ -719,7 +722,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
Op::Binary(op, _) => op.span,
Op::Unary(_, span) => span,
};
- let (opname, trait_did) = lang_item_for_op(self.tcx, op, span);
+ let (opname, Some(trait_did)) = lang_item_for_op(self.tcx, op, span) else {
+ // Bail if the operator trait is not defined.
+ return Err(vec![]);
+ };
debug!(
"lookup_op_method(lhs_ty={:?}, op={:?}, opname={:?}, trait_did={:?})",
@@ -753,24 +759,38 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
span,
traits::BinOp {
rhs_span: opt_rhs_expr.map(|expr| expr.span),
- is_lit: opt_rhs_expr
- .map_or(false, |expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
+ is_lit: opt_rhs_expr.is_some_and(|expr| matches!(expr.kind, hir::ExprKind::Lit(_))),
output_ty: expected.only_has_type(self),
},
);
- let method = trait_did.and_then(|trait_did| {
- self.lookup_method_in_trait(cause.clone(), opname, trait_did, lhs_ty, Some(input_types))
- });
-
- match (method, trait_did) {
- (Some(ok), _) => {
+ let method = self.lookup_method_in_trait(
+ cause.clone(),
+ opname,
+ trait_did,
+ lhs_ty,
+ Some(input_types),
+ );
+ match method {
+ Some(ok) => {
let method = self.register_infer_ok_obligations(ok);
self.select_obligations_where_possible(|_| {});
Ok(method)
}
- (None, None) => Err(vec![]),
- (None, Some(trait_did)) => {
+ None => {
+ // This path may do some inference, so make sure we've really
+ // doomed compilation so as to not accidentally stabilize new
+ // inference or something here...
+ self.tcx.sess.delay_span_bug(span, "this path really should be doomed...");
+ // Guide inference for the RHS expression if it's provided --
+ // this will allow us to better error reporting, at the expense
+ // of making some error messages a bit more specific.
+ if let Some((rhs_expr, rhs_ty)) = opt_rhs
+ && rhs_ty.is_ty_var()
+ {
+ self.check_expr_coercible_to_type(rhs_expr, rhs_ty, None);
+ }
+
let (obligation, _) =
self.obligation_for_method(cause, trait_did, lhs_ty, Some(input_types));
// FIXME: This should potentially just add the obligation to the `FnCtxt`
diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs
index af0bd26de..5af955d31 100644
--- a/compiler/rustc_hir_typeck/src/pat.rs
+++ b/compiler/rustc_hir_typeck/src/pat.rs
@@ -1,4 +1,4 @@
-use crate::{FnCtxt, RawTy};
+use crate::{errors, FnCtxt, RawTy};
use rustc_ast as ast;
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{
@@ -517,7 +517,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
fn endpoint_has_type(&self, err: &mut Diagnostic, span: Span, ty: Ty<'_>) {
if !ty.references_error() {
- err.span_label(span, &format!("this is of type `{}`", ty));
+ err.span_label(span, format!("this is of type `{}`", ty));
}
}
@@ -544,7 +544,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
format!("this is of type `{}` but it should be `char` or numeric", ty)
};
let mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| {
- err.span_label(first_span, &msg(first_ty));
+ err.span_label(first_span, msg(first_ty));
if let Some((_, ty, sp)) = second {
let ty = self.resolve_vars_if_possible(ty);
self.endpoint_has_type(&mut err, sp, ty);
@@ -552,8 +552,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
match (lhs, rhs) {
(Some((true, lhs_ty, lhs_sp)), Some((true, rhs_ty, rhs_sp))) => {
- err.span_label(lhs_sp, &msg(lhs_ty));
- err.span_label(rhs_sp, &msg(rhs_ty));
+ err.span_label(lhs_sp, msg(lhs_ty));
+ err.span_label(rhs_sp, msg(rhs_ty));
}
(Some((true, lhs_ty, lhs_sp)), rhs) => one_side_err(lhs_sp, lhs_ty, rhs),
(lhs, Some((true, rhs_ty, rhs_sp))) => one_side_err(rhs_sp, rhs_ty, lhs),
@@ -651,7 +651,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
)
});
let pre = if in_match { "in the same arm, " } else { "" };
- err.note(&format!("{}a binding must have the same type in all alternatives", pre));
+ err.note(format!("{}a binding must have the same type in all alternatives", pre));
self.suggest_adding_missing_ref_or_removing_ref(
&mut err,
span,
@@ -958,11 +958,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) {
let pat_span = pat.span;
if let Some(span) = self.tcx.hir().res_span(pat_res) {
- e.span_label(span, &format!("{} defined here", res.descr()));
+ e.span_label(span, format!("{} defined here", res.descr()));
if let [hir::PathSegment { ident, .. }] = &*segments {
e.span_label(
pat_span,
- &format!(
+ format!(
"`{}` is interpreted as {} {}, not a new binding",
ident,
res.article(),
@@ -1158,7 +1158,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_label(
last_subpat_span,
- &format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
+ format!("expected {} field{}, found {}", fields.len(), fields_ending, subpats.len()),
);
if self.tcx.sess.source_map().is_multiline(qpath.span().between(last_subpat_span)) {
err.span_label(qpath.span(), "");
@@ -1171,7 +1171,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
}
err.span_label(
last_field_def_span,
- &format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
+ format!("{} has {} field{}", res.descr(), fields.len(), fields_ending),
);
// Identify the case `Some(x, y)` where the expected type is e.g. `Option<(T, U)>`.
@@ -1410,12 +1410,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Report an error if an incorrect number of fields was specified.
if adt.is_union() {
if fields.len() != 1 {
- tcx.sess
- .struct_span_err(pat.span, "union patterns should have exactly one field")
- .emit();
+ tcx.sess.emit_err(errors::UnionPatMultipleFields { span: pat.span });
}
if has_rest_pat {
- tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit();
+ tcx.sess.emit_err(errors::UnionPatDotDot { span: pat.span });
}
} else if !unmentioned_fields.is_empty() {
let accessible_unmentioned_fields: Vec<_> = unmentioned_fields
@@ -1643,7 +1641,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let unmentioned_field = unmentioned_fields[0].1.name;
err.span_suggestion_short(
pat_field.ident.span,
- &format!(
+ format!(
"`{}` has a field named `{}`",
tcx.def_path_str(variant.def_id),
unmentioned_field
@@ -1659,7 +1657,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
if tcx.sess.teach(&err.get_code().unwrap()) {
err.note(
"This error indicates that a struct pattern attempted to \
- extract a non-existent field from a struct. Struct fields \
+ extract a nonexistent field from a struct. Struct fields \
are identified by the name used before the colon : so struct \
patterns should resemble the declaration of the struct type \
being matched.\n\n\
@@ -1833,7 +1831,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
lint.help(
"ensure that all fields are mentioned explicitly by adding the suggested fields",
);
- lint.note(&format!(
+ lint.note(format!(
"the pattern is of type `{}` and the `non_exhaustive_omitted_patterns` attribute was found",
ty,
));
@@ -1897,7 +1895,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
};
err.span_suggestion(
sp,
- &format!(
+ format!(
"include the missing field{} in the pattern{}",
pluralize!(len),
if have_inaccessible_fields { " and ignore the inaccessible fields" } else { "" }
@@ -1924,7 +1922,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
);
err.span_suggestion(
sp,
- &format!(
+ format!(
"if you don't care about {these} missing field{s}, you can explicitly ignore {them}",
these = pluralize!("this", len),
s = pluralize!(len),
diff --git a/compiler/rustc_hir_typeck/src/place_op.rs b/compiler/rustc_hir_typeck/src/place_op.rs
index 2cca45de5..e2b1dc007 100644
--- a/compiler/rustc_hir_typeck/src/place_op.rs
+++ b/compiler/rustc_hir_typeck/src/place_op.rs
@@ -73,16 +73,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let ty = self.resolve_vars_if_possible(ty);
let mut err = self.tcx.sess.struct_span_err(
span,
- &format!("negative integers cannot be used to index on a `{ty}`"),
+ format!("negative integers cannot be used to index on a `{ty}`"),
);
- err.span_label(span, &format!("cannot use a negative integer for indexing on `{ty}`"));
+ err.span_label(span, format!("cannot use a negative integer for indexing on `{ty}`"));
if let (hir::ExprKind::Path(..), Ok(snippet)) =
(&base_expr.kind, self.tcx.sess.source_map().span_to_snippet(base_expr.span))
{
// `foo[-1]` to `foo[foo.len() - 1]`
err.span_suggestion_verbose(
span.shrink_to_lo(),
- &format!(
+ format!(
"to access an element starting from the end of the `{ty}`, compute the index",
),
format!("{snippet}.len() "),
@@ -200,9 +200,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
- let (imm_tr, imm_op) = match op {
+ let (Some(imm_tr), imm_op) = (match op {
PlaceOp::Deref => (self.tcx.lang_items().deref_trait(), sym::deref),
PlaceOp::Index => (self.tcx.lang_items().index_trait(), sym::index),
+ }) else {
+ // Bail if `Deref` or `Index` isn't defined.
+ return None;
};
// If the lang item was declared incorrectly, stop here so that we don't
@@ -219,15 +222,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
- imm_tr.and_then(|trait_did| {
- self.lookup_method_in_trait(
- self.misc(span),
- Ident::with_dummy_span(imm_op),
- trait_did,
- base_ty,
- Some(arg_tys),
- )
- })
+ self.lookup_method_in_trait(
+ self.misc(span),
+ Ident::with_dummy_span(imm_op),
+ imm_tr,
+ base_ty,
+ Some(arg_tys),
+ )
}
fn try_mutable_overloaded_place_op(
@@ -239,9 +240,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
) -> Option<InferOk<'tcx, MethodCallee<'tcx>>> {
debug!("try_mutable_overloaded_place_op({:?},{:?},{:?})", span, base_ty, op);
- let (mut_tr, mut_op) = match op {
+ let (Some(mut_tr), mut_op) = (match op {
PlaceOp::Deref => (self.tcx.lang_items().deref_mut_trait(), sym::deref_mut),
PlaceOp::Index => (self.tcx.lang_items().index_mut_trait(), sym::index_mut),
+ }) else {
+ // Bail if `DerefMut` or `IndexMut` isn't defined.
+ return None;
};
// If the lang item was declared incorrectly, stop here so that we don't
@@ -258,15 +262,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
return None;
}
- mut_tr.and_then(|trait_did| {
- self.lookup_method_in_trait(
- self.misc(span),
- Ident::with_dummy_span(mut_op),
- trait_did,
- base_ty,
- Some(arg_tys),
- )
- })
+ self.lookup_method_in_trait(
+ self.misc(span),
+ Ident::with_dummy_span(mut_op),
+ mut_tr,
+ base_ty,
+ Some(arg_tys),
+ )
}
/// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index`
@@ -327,7 +329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514).
// This helps avoid accidental drops.
if inside_union
- && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop())
+ && source.ty_adt_def().is_some_and(|adt| adt.is_manually_drop())
{
let mut err = self.tcx.sess.struct_span_err(
expr.span,
diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs
index 41a6ad80b..9458099f5 100644
--- a/compiler/rustc_hir_typeck/src/upvar.rs
+++ b/compiler/rustc_hir_typeck/src/upvar.rs
@@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id);
if should_do_rust_2021_incompatible_closure_captures_analysis(self.tcx, closure_hir_id) {
- self.perform_2229_migration_anaysis(closure_def_id, body_id, capture_clause, span);
+ self.perform_2229_migration_analysis(closure_def_id, body_id, capture_clause, span);
}
let after_feature_tys = self.final_upvar_tys(closure_def_id);
@@ -713,7 +713,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.tcx.sess.delay_span_bug(
closure_span,
- &format!(
+ format!(
"two identical projections: ({:?}, {:?})",
capture1.place.projections, capture2.place.projections
),
@@ -731,7 +731,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
/// Perform the migration analysis for RFC 2229, and emit lint
/// `disjoint_capture_drop_reorder` if needed.
- fn perform_2229_migration_anaysis(
+ fn perform_2229_migration_analysis(
&self,
closure_def_id: LocalDefId,
body_id: hir::BodyId,
@@ -863,7 +863,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let indent = line2.split_once(|c: char| !c.is_whitespace()).unwrap_or_default().0;
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos::from_usize(line1.len())).shrink_to_lo(),
- &diagnostic_msg,
+ diagnostic_msg,
format!("\n{indent}{migration_string};"),
Applicability::MachineApplicable,
);
@@ -874,7 +874,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// directly after the `{`.
lint.span_suggestion(
closure_body_span.with_lo(closure_body_span.lo() + BytePos(1)).shrink_to_lo(),
- &diagnostic_msg,
+ diagnostic_msg,
format!(" {migration_string};"),
Applicability::MachineApplicable,
);
@@ -882,7 +882,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// This is a closure without braces around the body.
// We add braces to add the `let` before the body.
lint.multipart_suggestion(
- &diagnostic_msg,
+ diagnostic_msg,
vec![
(closure_body_span.shrink_to_lo(), format!("{{ {migration_string}; ")),
(closure_body_span.shrink_to_hi(), " }".to_string()),
@@ -893,7 +893,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
} else {
lint.span_suggestion(
closure_span,
- &diagnostic_msg,
+ diagnostic_msg,
migration_string,
Applicability::HasPlaceholders
);
@@ -972,15 +972,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let mut obligations_should_hold = Vec::new();
// Checks if a root variable implements any of the auto traits
for check_trait in auto_traits_def_id.iter() {
- obligations_should_hold.push(
- check_trait
- .map(|check_trait| {
- self.infcx
- .type_implements_trait(check_trait, [ty], self.param_env)
- .must_apply_modulo_regions()
- })
- .unwrap_or(false),
- );
+ obligations_should_hold.push(check_trait.is_some_and(|check_trait| {
+ self.infcx
+ .type_implements_trait(check_trait, [ty], self.param_env)
+ .must_apply_modulo_regions()
+ }));
}
let mut problematic_captures = FxHashMap::default();
@@ -996,15 +992,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
// Checks if a capture implements any of the auto traits
let mut obligations_holds_for_capture = Vec::new();
for check_trait in auto_traits_def_id.iter() {
- obligations_holds_for_capture.push(
- check_trait
- .map(|check_trait| {
- self.infcx
- .type_implements_trait(check_trait, [ty], self.param_env)
- .must_apply_modulo_regions()
- })
- .unwrap_or(false),
- );
+ obligations_holds_for_capture.push(check_trait.is_some_and(|check_trait| {
+ self.infcx
+ .type_implements_trait(check_trait, [ty], self.param_env)
+ .must_apply_modulo_regions()
+ }));
}
let mut capture_problems = FxHashSet::default();
@@ -1519,7 +1511,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
let span =
capture_info.path_expr_id.map_or(closure_span, |e| self.tcx.hir().span(e));
- diag.span_note(span, &output_str);
+ diag.span_note(span, output_str);
}
diag.emit();
}
@@ -1560,13 +1552,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
multi_span.push_span_label(path_span, path_label);
multi_span.push_span_label(capture_kind_span, capture_kind_label);
- diag.span_note(multi_span, &output_str);
+ diag.span_note(multi_span, output_str);
} else {
let span = capture_info
.path_expr_id
.map_or(closure_span, |e| self.tcx.hir().span(e));
- diag.span_note(span, &output_str);
+ diag.span_note(span, output_str);
};
}
}
diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs
index e876fa275..0f21fc1e6 100644
--- a/compiler/rustc_hir_typeck/src/writeback.rs
+++ b/compiler/rustc_hir_typeck/src/writeback.rs
@@ -5,11 +5,10 @@
use crate::FnCtxt;
use hir::def_id::LocalDefId;
use rustc_data_structures::fx::FxHashMap;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282;
-use rustc_infer::infer::InferCtxt;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::mir::FakeReadCause;
use rustc_middle::ty::adjustment::{Adjust, Adjustment, PointerCast};
@@ -70,6 +69,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.visit_user_provided_tys();
wbcx.visit_user_provided_sigs();
wbcx.visit_generator_interior_types();
+ wbcx.visit_offset_of_container_types();
wbcx.typeck_results.rvalue_scopes =
mem::take(&mut self.typeck_results.borrow_mut().rvalue_scopes);
@@ -82,10 +82,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
wbcx.typeck_results.treat_byte_string_as_slice =
mem::take(&mut self.typeck_results.borrow_mut().treat_byte_string_as_slice);
- if let Some(e) = self.tainted_by_errors() {
- wbcx.typeck_results.tainted_by_errors = Some(e);
- }
-
debug!("writeback: typeck results for {:?} are {:#?}", item_def_id, wbcx.typeck_results);
self.tcx.arena.alloc(wbcx.typeck_results)
@@ -118,12 +114,21 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
) -> WritebackCx<'cx, 'tcx> {
let owner = body.id().hir_id.owner;
- WritebackCx {
+ let mut wbcx = WritebackCx {
fcx,
typeck_results: ty::TypeckResults::new(owner),
body,
rustc_dump_user_substs,
+ };
+
+ // HACK: We specifically don't want the (opaque) error from tainting our
+ // inference context. That'll prevent us from doing opaque type inference
+ // later on in borrowck, which affects diagnostic spans pretty negatively.
+ if let Some(e) = fcx.tainted_by_errors() {
+ wbcx.typeck_results.tainted_by_errors = Some(e);
}
+
+ wbcx
}
fn tcx(&self) -> TyCtxt<'tcx> {
@@ -132,7 +137,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fn write_ty_to_typeck_results(&mut self, hir_id: hir::HirId, ty: Ty<'tcx>) {
debug!("write_ty_to_typeck_results({:?}, {:?})", hir_id, ty);
- assert!(!ty.needs_infer() && !ty.has_placeholders() && !ty.has_free_regions());
+ assert!(!ty.has_infer() && !ty.has_placeholders() && !ty.has_free_regions());
self.typeck_results.node_types_mut().insert(hir_id, ty);
}
@@ -226,7 +231,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// When encountering `return [0][0]` outside of a `fn` body we can encounter a base
// that isn't in the type table. We assume more relevant errors have already been
// emitted, so we delay an ICE if none have. (#64638)
- self.tcx().sess.delay_span_bug(e.span, &format!("bad base: `{:?}`", base));
+ self.tcx().sess.delay_span_bug(e.span, format!("bad base: `{:?}`", base));
}
if let Some(ty::Ref(_, base_ty, _)) = base_ty {
let index_ty = typeck_results.expr_ty_adjusted_opt(index).unwrap_or_else(|| {
@@ -236,7 +241,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
// error has been emitted. (#64638)
self.fcx.tcx.ty_error_with_message(
e.span,
- &format!("bad index {:?} for base: `{:?}`", index, base),
+ format!("bad index {:?} for base: `{:?}`", index, base),
)
});
let index_ty = self.fcx.resolve_vars_if_possible(index_ty);
@@ -295,7 +300,7 @@ impl<'cx, 'tcx> Visitor<'tcx> for WritebackCx<'cx, 'tcx> {
self.visit_field_id(field.hir_id);
}
}
- hir::ExprKind::Field(..) => {
+ hir::ExprKind::Field(..) | hir::ExprKind::OffsetOf(..) => {
self.visit_field_id(e.hir_id);
}
hir::ExprKind::ConstBlock(anon_const) => {
@@ -490,7 +495,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
let err = self
.tcx()
.sess
- .struct_span_err(span, &format!("user substs: {:?}", user_substs));
+ .struct_span_err(span, format!("user substs: {:?}", user_substs));
err.buffer(&mut errors_buffer);
}
}
@@ -507,7 +512,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
fcx_typeck_results.user_provided_types().items().map(|(local_id, c_ty)| {
let hir_id = hir::HirId { owner: common_hir_owner, local_id };
- if cfg!(debug_assertions) && c_ty.needs_infer() {
+ if cfg!(debug_assertions) && c_ty.has_infer() {
span_bug!(
hir_id.to_span(self.fcx.tcx),
"writeback: `{:?}` has inference variables",
@@ -526,7 +531,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
self.typeck_results.user_provided_sigs.extend(
fcx_typeck_results.user_provided_sigs.items().map(|(&def_id, c_sig)| {
- if cfg!(debug_assertions) && c_sig.needs_infer() {
+ if cfg!(debug_assertions) && c_sig.has_infer() {
span_bug!(
self.fcx.tcx.def_span(def_id),
"writeback: `{:?}` has inference variables",
@@ -578,13 +583,26 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
continue;
}
- let hidden_type = hidden_type.remap_generic_params_to_declaration_params(
- opaque_type_key,
- self.fcx.infcx.tcx,
- true,
- );
-
- self.typeck_results.concrete_opaque_types.insert(opaque_type_key.def_id, hidden_type);
+ let hidden_type =
+ self.tcx().erase_regions(hidden_type.remap_generic_params_to_declaration_params(
+ opaque_type_key,
+ self.tcx(),
+ true,
+ ));
+
+ if let Some(last_opaque_ty) = self
+ .typeck_results
+ .concrete_opaque_types
+ .insert(opaque_type_key.def_id, hidden_type)
+ && last_opaque_ty.ty != hidden_type.ty
+ {
+ hidden_type
+ .report_mismatch(&last_opaque_ty, opaque_type_key.def_id, self.tcx())
+ .stash(
+ self.tcx().def_span(opaque_type_key.def_id),
+ StashKey::OpaqueHiddenTypeMismatch,
+ );
+ }
}
}
@@ -617,7 +635,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
if let Some(substs) = self.fcx.typeck_results.borrow().node_substs_opt(hir_id) {
let substs = self.resolve(substs, &span);
debug!("write_substs_to_tcx({:?}, {:?})", hir_id, substs);
- assert!(!substs.needs_infer() && !substs.has_placeholders());
+ assert!(!substs.has_infer() && !substs.has_placeholders());
self.typeck_results.node_substs_mut().insert(hir_id, substs);
}
}
@@ -682,13 +700,27 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> {
}
}
+ fn visit_offset_of_container_types(&mut self) {
+ let fcx_typeck_results = self.fcx.typeck_results.borrow();
+ assert_eq!(fcx_typeck_results.hir_owner, self.typeck_results.hir_owner);
+ let common_hir_owner = fcx_typeck_results.hir_owner;
+
+ for (local_id, &(container, ref indices)) in
+ fcx_typeck_results.offset_of_data().items_in_stable_order()
+ {
+ let hir_id = hir::HirId { owner: common_hir_owner, local_id };
+ let container = self.resolve(container, &hir_id);
+ self.typeck_results.offset_of_data_mut().insert(hir_id, (container, indices.clone()));
+ }
+ }
+
fn resolve<T>(&mut self, x: T, span: &dyn Locatable) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
let mut resolver = Resolver::new(self.fcx, span, self.body);
let x = x.fold_with(&mut resolver);
- if cfg!(debug_assertions) && x.needs_infer() {
+ if cfg!(debug_assertions) && x.has_infer() {
span_bug!(span.to_span(self.fcx.tcx), "writeback: `{:?}` has inference variables", x);
}
@@ -722,8 +754,7 @@ impl Locatable for hir::HirId {
/// The Resolver. This is the type folding engine that detects
/// unresolved types and so forth.
struct Resolver<'cx, 'tcx> {
- tcx: TyCtxt<'tcx>,
- infcx: &'cx InferCtxt<'tcx>,
+ fcx: &'cx FnCtxt<'cx, 'tcx>,
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
@@ -737,18 +768,18 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> {
span: &'cx dyn Locatable,
body: &'tcx hir::Body<'tcx>,
) -> Resolver<'cx, 'tcx> {
- Resolver { tcx: fcx.tcx, infcx: fcx, span, body, replaced_with_error: None }
+ Resolver { fcx, span, body, replaced_with_error: None }
}
fn report_error(&self, p: impl Into<ty::GenericArg<'tcx>>) -> ErrorGuaranteed {
- match self.tcx.sess.has_errors() {
+ match self.fcx.tcx.sess.has_errors() {
Some(e) => e,
None => self
- .infcx
+ .fcx
.err_ctxt()
.emit_inference_failure_err(
- self.tcx.hir().body_owner_def_id(self.body.id()),
- self.span.to_span(self.tcx),
+ self.fcx.tcx.hir().body_owner_def_id(self.body.id()),
+ self.span.to_span(self.fcx.tcx),
p.into(),
E0282,
false,
@@ -780,40 +811,46 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for EraseEarlyRegions<'tcx> {
impl<'cx, 'tcx> TypeFolder<TyCtxt<'tcx>> for Resolver<'cx, 'tcx> {
fn interner(&self) -> TyCtxt<'tcx> {
- self.tcx
+ self.fcx.tcx
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- match self.infcx.fully_resolve(t) {
+ match self.fcx.fully_resolve(t) {
+ Ok(t) if self.fcx.tcx.trait_solver_next() => {
+ // We must normalize erasing regions here, since later lints
+ // expect that types that show up in the typeck are fully
+ // normalized.
+ self.fcx.tcx.try_normalize_erasing_regions(self.fcx.param_env, t).unwrap_or(t)
+ }
Ok(t) => {
// Do not anonymize late-bound regions
// (e.g. keep `for<'a>` named `for<'a>`).
// This allows NLL to generate error messages that
// refer to the higher-ranked lifetime names written by the user.
- EraseEarlyRegions { tcx: self.tcx }.fold_ty(t)
+ EraseEarlyRegions { tcx: self.fcx.tcx }.fold_ty(t)
}
Err(_) => {
debug!("Resolver::fold_ty: input type `{:?}` not fully resolvable", t);
let e = self.report_error(t);
self.replaced_with_error = Some(e);
- self.interner().ty_error(e)
+ self.fcx.tcx.ty_error(e)
}
}
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
debug_assert!(!r.is_late_bound(), "Should not be resolving bound region.");
- self.tcx.lifetimes.re_erased
+ self.fcx.tcx.lifetimes.re_erased
}
fn fold_const(&mut self, ct: ty::Const<'tcx>) -> ty::Const<'tcx> {
- match self.infcx.fully_resolve(ct) {
- Ok(ct) => self.tcx.erase_regions(ct),
+ match self.fcx.fully_resolve(ct) {
+ Ok(ct) => self.fcx.tcx.erase_regions(ct),
Err(_) => {
debug!("Resolver::fold_const: input const `{:?}` not fully resolvable", ct);
let e = self.report_error(ct);
self.replaced_with_error = Some(e);
- self.interner().const_error_with_guaranteed(ct.ty(), e)
+ self.fcx.tcx.const_error(ct.ty(), e)
}
}
}
diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml
index ad8939395..59a0623c1 100644
--- a/compiler/rustc_incremental/Cargo.toml
+++ b/compiler/rustc_incremental/Cargo.toml
@@ -11,6 +11,7 @@ rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_fs_util = { path = "../rustc_fs_util" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl
index b760620e3..9fa4e0fb2 100644
--- a/compiler/rustc_incremental/messages.ftl
+++ b/compiler/rustc_incremental/messages.ftl
@@ -1,118 +1,118 @@
-incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
+incremental_assert_loaded =
+ we asserted that an existing incremental cache directory should be successfully loaded, but it was not
-incremental_missing_depnode = missing `DepNode` variant
+incremental_assert_not_loaded =
+ we asserted that the incremental cache should not be loaded, but it was loaded
-incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
+incremental_assertion_auto =
+ `except` specified DepNodes that can not be affected for "{$name}": "{$e}"
-incremental_no_path = no path from `{$source}` to `{$target}`
+incremental_associated_value_expected = expected an associated value
-incremental_ok = OK
+incremental_associated_value_expected_for = associated value expected for `{$ident}`
-incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
+incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err}
-incremental_missing_query_depgraph =
- found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
+incremental_cargo_help_1 =
+ incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)
+incremental_cargo_help_2 =
+ the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)
-incremental_malformed_cgu_name =
- found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
+incremental_copy_workproduct_to_cache =
+ error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
-incremental_no_module_named =
- no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
+incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
-incremental_field_associated_value_expected = associated value expected for `{$name}`
+incremental_create_incr_comp_dir =
+ could not create incremental compilation {$tag} directory `{$path}`: {$err}
-incremental_no_field = no field `{$name}`
+incremental_create_lock =
+ incremental compilation: could not create session directory lock file: {$lock_err}
+incremental_create_new = failed to create {$name} at `{$path}`: {$err}
-incremental_assertion_auto =
- `except` specified DepNodes that can not be affected for "{$name}": "{$e}"
+incremental_decode_incr_cache = could not decode incremental cache: {$err}
-incremental_undefined_clean_dirty_assertions_item =
- clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
+incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err}
-incremental_undefined_clean_dirty_assertions =
- clean/dirty auto-assertions not yet defined for {$kind}
+incremental_delete_incompatible =
+ failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err}
-incremental_repeated_depnode_label = dep-node label `{$label}` is repeated
+incremental_delete_lock =
+ error deleting lock file for incremental compilation session directory `{$path}`: {$err}
-incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
+incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err}
-incremental_not_dirty = `{$dep_node_str}` should be dirty but is not
+incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err}
-incremental_not_clean = `{$dep_node_str}` should be clean but is not
+incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
-incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not
+incremental_field_associated_value_expected = associated value expected for `{$name}`
-incremental_unknown_item = unknown item `{$name}`
+incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
-incremental_no_cfg = no cfg attribute
+incremental_finalized_gc_failed =
+ failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err}
-incremental_associated_value_expected_for = associated value expected for `{$ident}`
+incremental_hard_link_failed =
+ hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}`
-incremental_associated_value_expected = expected an associated value
+incremental_invalid_gc_failed =
+ failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err}
-incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute
+incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err}
-incremental_delete_old = unable to delete old {$name} at `{$path}`: {$err}
+incremental_lock_unsupported =
+ the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation
+incremental_malformed_cgu_name =
+ found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case).
-incremental_create_new = failed to create {$name} at `{$path}`: {$err}
+incremental_missing_depnode = missing `DepNode` variant
-incremental_write_new = failed to write {$name} to `{$path}`: {$err}
+incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected
-incremental_canonicalize_path = incremental compilation: error canonicalizing path `{$path}`: {$err}
+incremental_missing_query_depgraph =
+ found CGU-reuse attribute but `-Zquery-dep-graph` was not specified
-incremental_create_incr_comp_dir =
- could not create incremental compilation {$tag} directory `{$path}`: {$err}
+incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err}
-incremental_create_lock =
- incremental compilation: could not create session directory lock file: {$lock_err}
-incremental_lock_unsupported =
- the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation
-incremental_cargo_help_1 =
- incremental compilation can be disabled by setting the environment variable CARGO_INCREMENTAL=0 (see https://doc.rust-lang.org/cargo/reference/profiles.html#incremental)
-incremental_cargo_help_2 =
- the entire build directory can be changed to a different filesystem by setting the environment variable CARGO_TARGET_DIR to a different path (see https://doc.rust-lang.org/cargo/reference/config.html#buildtarget-dir)
+incremental_no_cfg = no cfg attribute
-incremental_delete_lock =
- error deleting lock file for incremental compilation session directory `{$path}`: {$err}
+incremental_no_field = no field `{$name}`
-incremental_hard_link_failed =
- hard linking files in the incremental compilation cache failed. copying files instead. consider moving the cache directory to a file system which supports hard linking in session dir `{$path}`
+incremental_no_module_named =
+ no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names}
-incremental_delete_partial = failed to delete partly initialized session dir `{$path}`: {$err}
+incremental_no_path = no path from `{$source}` to `{$target}`
-incremental_delete_full = error deleting incremental compilation session directory `{$path}`: {$err}
+incremental_not_clean = `{$dep_node_str}` should be clean but is not
-incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err}
+incremental_not_dirty = `{$dep_node_str}` should be dirty but is not
-incremental_invalid_gc_failed =
- failed to garbage collect invalid incremental compilation session directory `{$path}`: {$err}
+incremental_not_loaded = `{$dep_node_str}` should have been loaded from disk but it was not
-incremental_finalized_gc_failed =
- failed to garbage collect finalized incremental compilation session directory `{$path}`: {$err}
+incremental_ok = OK
+
+incremental_repeated_depnode_label = dep-node label `{$label}` is repeated
incremental_session_gc_failed =
failed to garbage collect incremental compilation session directory `{$path}`: {$err}
-incremental_assert_not_loaded =
- we asserted that the incremental cache should not be loaded, but it was loaded
-
-incremental_assert_loaded =
- we asserted that an existing incremental cache directory should be successfully loaded, but it was not
+incremental_unchecked_clean = found unchecked `#[rustc_clean]` attribute
-incremental_delete_incompatible =
- failed to delete invalidated or incompatible incremental compilation session directory contents `{$path}`: {$err}
+incremental_undefined_clean_dirty_assertions =
+ clean/dirty auto-assertions not yet defined for {$kind}
-incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err}
+incremental_undefined_clean_dirty_assertions_item =
+ clean/dirty auto-assertions not yet defined for Node::Item.node={$kind}
-incremental_decode_incr_cache = could not decode incremental cache: {$err}
+incremental_unknown_item = unknown item `{$name}`
-incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
+incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified
-incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err}
+incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name}
-incremental_create_dep_graph = failed to create dependency graph at `{$path}`: {$err}
+incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized
-incremental_copy_workproduct_to_cache =
- error copying object file `{$from}` to incremental directory as `{$to}`: {$err}
+incremental_write_dep_graph = failed to write dependency graph to `{$path}`: {$err}
-incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err}
+incremental_write_new = failed to write {$name} to `{$path}`: {$err}
diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs
index df958e4a6..11710c368 100644
--- a/compiler/rustc_incremental/src/lib.rs
+++ b/compiler/rustc_incremental/src/lib.rs
@@ -33,6 +33,6 @@ pub use persist::LoadResult;
pub use persist::{build_dep_graph, load_dep_graph, DepGraphFuture};
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
fluent_messages! { "../messages.ftl" }
diff --git a/compiler/rustc_incremental/src/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs
index 1d88dfd20..43274091c 100644
--- a/compiler/rustc_incremental/src/persist/dirty_clean.rs
+++ b/compiler/rustc_incremental/src/persist/dirty_clean.rs
@@ -139,7 +139,7 @@ pub fn check_dirty_clean_annotations(tcx: TyCtxt<'_>) {
return;
}
- // can't add `#[rustc_clean]` etc without opting in to this feature
+ // can't add `#[rustc_clean]` etc without opting into this feature
if !tcx.features().rustc_attrs {
return;
}
diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs
index dc981c617..25bf83f64 100644
--- a/compiler/rustc_incremental/src/persist/file_format.rs
+++ b/compiler/rustc_incremental/src/persist/file_format.rs
@@ -14,6 +14,7 @@ use rustc_data_structures::memmap::Mmap;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use rustc_serialize::Encoder;
use rustc_session::Session;
+use std::borrow::Cow;
use std::env;
use std::fs;
use std::io::{self, Read};
@@ -25,17 +26,12 @@ const FILE_MAGIC: &[u8] = b"RSIC";
/// Change this if the header format changes.
const HEADER_FORMAT_VERSION: u16 = 0;
-/// A version string that hopefully is always different for compiler versions
-/// with different encodings of incremental compilation artifacts. Contains
-/// the Git commit hash.
-const RUSTC_VERSION: Option<&str> = option_env!("CFG_VERSION");
-
-pub(crate) fn write_file_header(stream: &mut FileEncoder, nightly_build: bool) {
+pub(crate) fn write_file_header(stream: &mut FileEncoder, sess: &Session) {
stream.emit_raw_bytes(FILE_MAGIC);
stream
.emit_raw_bytes(&[(HEADER_FORMAT_VERSION >> 0) as u8, (HEADER_FORMAT_VERSION >> 8) as u8]);
- let rustc_version = rustc_version(nightly_build);
+ let rustc_version = rustc_version(sess.is_nightly_build(), sess.cfg_version);
assert_eq!(rustc_version.len(), (rustc_version.len() as u8) as usize);
stream.emit_raw_bytes(&[rustc_version.len() as u8]);
stream.emit_raw_bytes(rustc_version.as_bytes());
@@ -73,7 +69,7 @@ where
}
};
- write_file_header(&mut encoder, sess.is_nightly_build());
+ write_file_header(&mut encoder, sess);
match encode(encoder) {
Ok(position) => {
@@ -100,9 +96,10 @@ where
/// - Returns `Err(..)` if some kind of IO error occurred while reading the
/// file.
pub fn read_file(
- report_incremental_info: bool,
path: &Path,
- nightly_build: bool,
+ report_incremental_info: bool,
+ is_nightly_build: bool,
+ cfg_version: &'static str,
) -> io::Result<Option<(Mmap, usize)>> {
let file = match fs::File::open(path) {
Ok(file) => file,
@@ -152,7 +149,7 @@ pub fn read_file(
let mut buffer = vec![0; rustc_version_str_len];
file.read_exact(&mut buffer)?;
- if buffer != rustc_version(nightly_build).as_bytes() {
+ if buffer != rustc_version(is_nightly_build, cfg_version).as_bytes() {
report_format_mismatch(report_incremental_info, path, "Different compiler version");
return Ok(None);
}
@@ -174,17 +171,15 @@ fn report_format_mismatch(report_incremental_info: bool, file: &Path, message: &
}
}
-fn rustc_version(nightly_build: bool) -> String {
+/// A version string that hopefully is always different for compiler versions
+/// with different encodings of incremental compilation artifacts. Contains
+/// the Git commit hash.
+fn rustc_version(nightly_build: bool, cfg_version: &'static str) -> Cow<'static, str> {
if nightly_build {
- if let Some(val) = env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
- return val.to_string_lossy().into_owned();
+ if let Ok(val) = env::var("RUSTC_FORCE_RUSTC_VERSION") {
+ return val.into();
}
}
- RUSTC_VERSION
- .expect(
- "Cannot use rustc without explicit version for \
- incremental compilation",
- )
- .to_string()
+ cfg_version.into()
}
diff --git a/compiler/rustc_incremental/src/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs
index d6f83838a..e3c688b3e 100644
--- a/compiler/rustc_incremental/src/persist/fs.rs
+++ b/compiler/rustc_incremental/src/persist/fs.rs
@@ -346,7 +346,7 @@ pub fn finalize_session_directory(sess: &Session, svh: Option<Svh>) {
let mut new_sub_dir_name = String::from(&old_sub_dir_name[..=dash_indices[2]]);
// Append the svh
- base_n::push_str(svh.as_u64() as u128, INT_ENCODE_BASE, &mut new_sub_dir_name);
+ base_n::push_str(svh.as_u128(), INT_ENCODE_BASE, &mut new_sub_dir_name);
// Create the full path
let new_path = incr_comp_session_dir.parent().unwrap().join(new_sub_dir_name);
@@ -601,7 +601,7 @@ fn string_to_timestamp(s: &str) -> Result<SystemTime, ()> {
fn crate_path(sess: &Session, crate_name: Symbol, stable_crate_id: StableCrateId) -> PathBuf {
let incr_dir = sess.opts.incremental.as_ref().unwrap().clone();
- let stable_crate_id = base_n::encode(stable_crate_id.to_u64() as u128, INT_ENCODE_BASE);
+ let stable_crate_id = base_n::encode(stable_crate_id.as_u64() as u128, INT_ENCODE_BASE);
let crate_name = format!("{}-{}", crate_name, stable_crate_id);
incr_dir.join(crate_name)
diff --git a/compiler/rustc_incremental/src/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs
index d5097065d..a4407a93f 100644
--- a/compiler/rustc_incremental/src/persist/load.rs
+++ b/compiler/rustc_incremental/src/persist/load.rs
@@ -4,7 +4,7 @@ use crate::errors;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::memmap::Mmap;
use rustc_middle::dep_graph::{SerializedDepGraph, WorkProduct, WorkProductId};
-use rustc_middle::ty::OnDiskCache;
+use rustc_middle::query::on_disk_cache::OnDiskCache;
use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::Decodable;
use rustc_session::config::IncrementalStateAssertion;
@@ -73,12 +73,22 @@ impl<T: Default> LoadResult<T> {
}
}
-fn load_data(
- report_incremental_info: bool,
+fn load_data(path: &Path, sess: &Session) -> LoadResult<(Mmap, usize)> {
+ load_data_no_sess(
+ path,
+ sess.opts.unstable_opts.incremental_info,
+ sess.is_nightly_build(),
+ sess.cfg_version,
+ )
+}
+
+fn load_data_no_sess(
path: &Path,
- nightly_build: bool,
+ report_incremental_info: bool,
+ is_nightly_build: bool,
+ cfg_version: &'static str,
) -> LoadResult<(Mmap, usize)> {
- match file_format::read_file(report_incremental_info, path, nightly_build) {
+ match file_format::read_file(path, report_incremental_info, is_nightly_build, cfg_version) {
Ok(Some(data_and_pos)) => LoadResult::Ok { data: data_and_pos },
Ok(None) => {
// The file either didn't exist or was produced by an incompatible
@@ -138,14 +148,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
let expected_hash = sess.opts.dep_tracking_hash(false);
let mut prev_work_products = FxHashMap::default();
- let nightly_build = sess.is_nightly_build();
// If we are only building with -Zquery-dep-graph but without an actual
// incr. comp. session directory, we skip this. Otherwise we'd fail
// when trying to load work products.
if sess.incr_comp_session_dir_opt().is_some() {
let work_products_path = work_products_path(sess);
- let load_result = load_data(report_incremental_info, &work_products_path, nightly_build);
+ let load_result = load_data(&work_products_path, sess);
if let LoadResult::Ok { data: (work_products_data, start_pos) } = load_result {
// Decode the list of work_products
@@ -173,10 +182,13 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
}
}
+ let is_nightly_build = sess.is_nightly_build();
+ let cfg_version = sess.cfg_version;
+
MaybeAsync::Async(std::thread::spawn(move || {
let _prof_timer = prof.generic_activity("incr_comp_load_dep_graph");
- match load_data(report_incremental_info, &path, nightly_build) {
+ match load_data_no_sess(&path, report_incremental_info, is_nightly_build, cfg_version) {
LoadResult::DataOutOfDate => LoadResult::DataOutOfDate,
LoadResult::LoadDepGraph(path, err) => LoadResult::LoadDepGraph(path, err),
LoadResult::DecodeIncrCache(err) => LoadResult::DecodeIncrCache(err),
@@ -211,19 +223,17 @@ pub fn load_dep_graph(sess: &Session) -> DepGraphFuture {
/// If we are not in incremental compilation mode, returns `None`.
/// Otherwise, tries to load the query result cache from disk,
/// creating an empty cache if it could not be loaded.
-pub fn load_query_result_cache<'a, C: OnDiskCache<'a>>(sess: &'a Session) -> Option<C> {
+pub fn load_query_result_cache(sess: &Session) -> Option<OnDiskCache<'_>> {
if sess.opts.incremental.is_none() {
return None;
}
let _prof_timer = sess.prof.generic_activity("incr_comp_load_query_result_cache");
- match load_data(
- sess.opts.unstable_opts.incremental_info,
- &query_cache_path(sess),
- sess.is_nightly_build(),
- ) {
- LoadResult::Ok { data: (bytes, start_pos) } => Some(C::new(sess, bytes, start_pos)),
- _ => Some(C::new_empty(sess.source_map())),
+ match load_data(&query_cache_path(sess), sess) {
+ LoadResult::Ok { data: (bytes, start_pos) } => {
+ Some(OnDiskCache::new(sess, bytes, start_pos))
+ }
+ _ => Some(OnDiskCache::new_empty(sess.source_map())),
}
}
diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs
index 27be56eac..7376be6be 100644
--- a/compiler/rustc_incremental/src/persist/save.rs
+++ b/compiler/rustc_incremental/src/persist/save.rs
@@ -48,7 +48,7 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) {
move || {
sess.time("incr_comp_persist_result_cache", || {
// Drop the memory map so that we can remove the file and write to it.
- if let Some(odc) = &tcx.on_disk_cache {
+ if let Some(odc) = &tcx.query_system.on_disk_cache {
odc.drop_serialized_data(tcx);
}
@@ -164,7 +164,7 @@ pub fn build_dep_graph(
}
};
- file_format::write_file_header(&mut encoder, sess.is_nightly_build());
+ file_format::write_file_header(&mut encoder, sess);
// First encode the commandline arguments hash
sess.opts.dep_tracking_hash(false).encode(&mut encoder);
diff --git a/compiler/rustc_index/src/bit_set.rs b/compiler/rustc_index/src/bit_set.rs
index 271ab8306..15bc3b4e3 100644
--- a/compiler/rustc_index/src/bit_set.rs
+++ b/compiler/rustc_index/src/bit_set.rs
@@ -1,6 +1,3 @@
-use crate::vec::{Idx, IndexVec};
-use arrayvec::ArrayVec;
-use smallvec::{smallvec, SmallVec};
use std::fmt;
use std::iter;
use std::marker::PhantomData;
@@ -9,8 +6,13 @@ use std::ops::{BitAnd, BitAndAssign, BitOrAssign, Bound, Not, Range, RangeBounds
use std::rc::Rc;
use std::slice;
+use arrayvec::ArrayVec;
+use smallvec::{smallvec, SmallVec};
+
use rustc_macros::{Decodable, Encodable};
+use crate::{Idx, IndexVec};
+
use Chunk::*;
#[cfg(test)]
@@ -1542,7 +1544,7 @@ impl<T: Idx> GrowableBitSet<T> {
#[inline]
pub fn contains(&self, elem: T) -> bool {
let (word_index, mask) = word_index_and_mask(elem);
- self.bit_set.words.get(word_index).map_or(false, |word| (word & mask) != 0)
+ self.bit_set.words.get(word_index).is_some_and(|word| (word & mask) != 0)
}
#[inline]
@@ -1816,7 +1818,7 @@ impl<R: Idx, C: Idx> SparseBitMatrix<R, C> {
/// if the matrix represents (transitive) reachability, can
/// `row` reach `column`?
pub fn contains(&self, row: R, column: C) -> bool {
- self.row(row).map_or(false, |r| r.contains(column))
+ self.row(row).is_some_and(|r| r.contains(column))
}
/// Adds the bits from row `read` to the bits from row `write`, and
diff --git a/compiler/rustc_index/src/idx.rs b/compiler/rustc_index/src/idx.rs
new file mode 100644
index 000000000..b85160540
--- /dev/null
+++ b/compiler/rustc_index/src/idx.rs
@@ -0,0 +1,45 @@
+use std::fmt::Debug;
+use std::hash::Hash;
+
+/// Represents some newtyped `usize` wrapper.
+///
+/// Purpose: avoid mixing indexes for different bitvector domains.
+pub trait Idx: Copy + 'static + Eq + PartialEq + Debug + Hash {
+ fn new(idx: usize) -> Self;
+
+ fn index(self) -> usize;
+
+ #[inline]
+ fn increment_by(&mut self, amount: usize) {
+ *self = self.plus(amount);
+ }
+
+ #[inline]
+ #[must_use = "Use `increment_by` if you wanted to update the index in-place"]
+ fn plus(self, amount: usize) -> Self {
+ Self::new(self.index() + amount)
+ }
+}
+
+impl Idx for usize {
+ #[inline]
+ fn new(idx: usize) -> Self {
+ idx
+ }
+ #[inline]
+ fn index(self) -> usize {
+ self
+ }
+}
+
+impl Idx for u32 {
+ #[inline]
+ fn new(idx: usize) -> Self {
+ assert!(idx <= u32::MAX as usize);
+ idx as u32
+ }
+ #[inline]
+ fn index(self) -> usize {
+ self as usize
+ }
+}
diff --git a/compiler/rustc_index/src/interval.rs b/compiler/rustc_index/src/interval.rs
index d809740c6..d3cf267dc 100644
--- a/compiler/rustc_index/src/interval.rs
+++ b/compiler/rustc_index/src/interval.rs
@@ -3,10 +3,11 @@ use std::marker::PhantomData;
use std::ops::RangeBounds;
use std::ops::{Bound, Range};
-use crate::vec::Idx;
-use crate::vec::IndexVec;
use smallvec::SmallVec;
+use crate::idx::Idx;
+use crate::vec::IndexVec;
+
#[cfg(test)]
mod tests;
@@ -180,6 +181,30 @@ impl<I: Idx> IntervalSet<I> {
self.map.is_empty()
}
+ /// Equivalent to `range.iter().find(|i| !self.contains(i))`.
+ pub fn first_unset_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
+ let start = inclusive_start(range.clone());
+ let Some(end) = inclusive_end(self.domain, range) else {
+ // empty range
+ return None;
+ };
+ if start > end {
+ return None;
+ }
+ let Some(last) = self.map.partition_point(|r| r.0 <= start).checked_sub(1) else {
+ // All ranges in the map start after the new range's end
+ return Some(I::new(start as usize));
+ };
+ let (_, prev_end) = self.map[last];
+ if start > prev_end {
+ Some(I::new(start as usize))
+ } else if prev_end < end {
+ Some(I::new(prev_end as usize + 1))
+ } else {
+ None
+ }
+ }
+
/// Returns the maximum (last) element present in the set from `range`.
pub fn last_set_in(&self, range: impl RangeBounds<I> + Clone) -> Option<I> {
let start = inclusive_start(range.clone());
@@ -223,7 +248,7 @@ impl<I: Idx> IntervalSet<I> {
fn check_invariants(&self) -> bool {
let mut current: Option<u32> = None;
for (start, end) in &self.map {
- if start > end || current.map_or(false, |x| x + 1 >= *start) {
+ if start > end || current.is_some_and(|x| x + 1 >= *start) {
return false;
}
current = Some(*end);
@@ -261,8 +286,7 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
}
fn ensure_row(&mut self, row: R) -> &mut IntervalSet<C> {
- self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size));
- &mut self.rows[row]
+ self.rows.ensure_contains_elem(row, || IntervalSet::new(self.column_size))
}
pub fn union_row(&mut self, row: R, from: &IntervalSet<C>) -> bool
@@ -297,6 +321,6 @@ impl<R: Idx, C: Step + Idx> SparseIntervalMatrix<R, C> {
}
pub fn contains(&self, row: R, point: C) -> bool {
- self.row(row).map_or(false, |r| r.contains(point))
+ self.row(row).is_some_and(|r| r.contains(point))
}
}
diff --git a/compiler/rustc_index/src/lib.rs b/compiler/rustc_index/src/lib.rs
index db2c79152..6fd9f34b2 100644
--- a/compiler/rustc_index/src/lib.rs
+++ b/compiler/rustc_index/src/lib.rs
@@ -17,7 +17,12 @@
pub mod bit_set;
#[cfg(feature = "nightly")]
pub mod interval;
-pub mod vec;
+
+mod idx;
+mod slice;
+mod vec;
+
+pub use {idx::Idx, slice::IndexSlice, vec::IndexVec};
#[cfg(feature = "rustc_macros")]
pub use rustc_macros::newtype_index;
diff --git a/compiler/rustc_index/src/slice.rs b/compiler/rustc_index/src/slice.rs
new file mode 100644
index 000000000..0663c7247
--- /dev/null
+++ b/compiler/rustc_index/src/slice.rs
@@ -0,0 +1,256 @@
+use std::{
+ fmt,
+ marker::PhantomData,
+ ops::{Index, IndexMut},
+ slice,
+};
+
+use crate::{Idx, IndexVec};
+
+/// A view into contiguous `T`s, indexed by `I` rather than by `usize`.
+///
+/// One common pattern you'll see is code that uses [`IndexVec::from_elem`]
+/// to create the storage needed for a particular "universe" (aka the set of all
+/// the possible keys that need an associated value) then passes that working
+/// area as `&mut IndexSlice<I, T>` to clarify that nothing will be added nor
+/// removed during processing (and, as a bonus, to chase fewer pointers).
+#[derive(PartialEq, Eq, Hash)]
+#[repr(transparent)]
+pub struct IndexSlice<I: Idx, T> {
+ _marker: PhantomData<fn(&I)>,
+ pub raw: [T],
+}
+
+impl<I: Idx, T> IndexSlice<I, T> {
+ #[inline]
+ pub const fn empty() -> &'static Self {
+ Self::from_raw(&[])
+ }
+
+ #[inline]
+ pub const fn from_raw(raw: &[T]) -> &Self {
+ let ptr: *const [T] = raw;
+ // SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
+ unsafe { &*(ptr as *const Self) }
+ }
+
+ #[inline]
+ pub fn from_raw_mut(raw: &mut [T]) -> &mut Self {
+ let ptr: *mut [T] = raw;
+ // SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
+ unsafe { &mut *(ptr as *mut Self) }
+ }
+
+ #[inline]
+ pub const fn len(&self) -> usize {
+ self.raw.len()
+ }
+
+ #[inline]
+ pub const fn is_empty(&self) -> bool {
+ self.raw.is_empty()
+ }
+
+ /// Gives the next index that will be assigned when `push` is called.
+ ///
+ /// Manual bounds checks can be done using `idx < slice.next_index()`
+ /// (as opposed to `idx.index() < slice.len()`).
+ #[inline]
+ pub fn next_index(&self) -> I {
+ I::new(self.len())
+ }
+
+ #[inline]
+ pub fn iter(&self) -> slice::Iter<'_, T> {
+ self.raw.iter()
+ }
+
+ #[inline]
+ pub fn iter_enumerated(
+ &self,
+ ) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator + '_ {
+ self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
+ }
+
+ #[inline]
+ pub fn indices(
+ &self,
+ ) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + Clone + 'static {
+ (0..self.len()).map(|n| I::new(n))
+ }
+
+ #[inline]
+ pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
+ self.raw.iter_mut()
+ }
+
+ #[inline]
+ pub fn iter_enumerated_mut(
+ &mut self,
+ ) -> impl DoubleEndedIterator<Item = (I, &mut T)> + ExactSizeIterator + '_ {
+ self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
+ }
+
+ #[inline]
+ pub fn last_index(&self) -> Option<I> {
+ self.len().checked_sub(1).map(I::new)
+ }
+
+ #[inline]
+ pub fn swap(&mut self, a: I, b: I) {
+ self.raw.swap(a.index(), b.index())
+ }
+
+ #[inline]
+ pub fn get(&self, index: I) -> Option<&T> {
+ self.raw.get(index.index())
+ }
+
+ #[inline]
+ pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
+ self.raw.get_mut(index.index())
+ }
+
+ /// Returns mutable references to two distinct elements, `a` and `b`.
+ ///
+ /// Panics if `a == b`.
+ #[inline]
+ pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
+ let (ai, bi) = (a.index(), b.index());
+ assert!(ai != bi);
+
+ if ai < bi {
+ let (c1, c2) = self.raw.split_at_mut(bi);
+ (&mut c1[ai], &mut c2[0])
+ } else {
+ let (c2, c1) = self.pick2_mut(b, a);
+ (c1, c2)
+ }
+ }
+
+ /// Returns mutable references to three distinct elements.
+ ///
+ /// Panics if the elements are not distinct.
+ #[inline]
+ pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
+ let (ai, bi, ci) = (a.index(), b.index(), c.index());
+ assert!(ai != bi && bi != ci && ci != ai);
+ let len = self.raw.len();
+ assert!(ai < len && bi < len && ci < len);
+ let ptr = self.raw.as_mut_ptr();
+ unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) }
+ }
+
+ #[inline]
+ pub fn binary_search(&self, value: &T) -> Result<I, I>
+ where
+ T: Ord,
+ {
+ match self.raw.binary_search(value) {
+ Ok(i) => Ok(Idx::new(i)),
+ Err(i) => Err(Idx::new(i)),
+ }
+ }
+}
+
+impl<I: Idx, J: Idx> IndexSlice<I, J> {
+ /// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`,
+ /// assuming the values in `self` are a permutation of `0..self.len()`.
+ ///
+ /// This is used to go between `memory_index` (source field order to memory order)
+ /// and `inverse_memory_index` (memory order to source field order).
+ /// See also `FieldsShape::Arbitrary::memory_index` for more details.
+ // FIXME(eddyb) build a better abstraction for permutations, if possible.
+ pub fn invert_bijective_mapping(&self) -> IndexVec<J, I> {
+ debug_assert_eq!(
+ self.iter().map(|x| x.index() as u128).sum::<u128>(),
+ (0..self.len() as u128).sum::<u128>(),
+ "The values aren't 0..N in input {self:?}",
+ );
+
+ let mut inverse = IndexVec::from_elem_n(Idx::new(0), self.len());
+ for (i1, &i2) in self.iter_enumerated() {
+ inverse[i2] = i1;
+ }
+
+ debug_assert_eq!(
+ inverse.iter().map(|x| x.index() as u128).sum::<u128>(),
+ (0..inverse.len() as u128).sum::<u128>(),
+ "The values aren't 0..N in result {self:?}",
+ );
+
+ inverse
+ }
+}
+
+impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexSlice<I, T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.raw, fmt)
+ }
+}
+
+impl<I: Idx, T> Index<I> for IndexSlice<I, T> {
+ type Output = T;
+
+ #[inline]
+ fn index(&self, index: I) -> &T {
+ &self.raw[index.index()]
+ }
+}
+
+impl<I: Idx, T> IndexMut<I> for IndexSlice<I, T> {
+ #[inline]
+ fn index_mut(&mut self, index: I) -> &mut T {
+ &mut self.raw[index.index()]
+ }
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a IndexSlice<I, T> {
+ type Item = &'a T;
+ type IntoIter = slice::Iter<'a, T>;
+
+ #[inline]
+ fn into_iter(self) -> slice::Iter<'a, T> {
+ self.raw.iter()
+ }
+}
+
+impl<'a, I: Idx, T> IntoIterator for &'a mut IndexSlice<I, T> {
+ type Item = &'a mut T;
+ type IntoIter = slice::IterMut<'a, T>;
+
+ #[inline]
+ fn into_iter(self) -> slice::IterMut<'a, T> {
+ self.raw.iter_mut()
+ }
+}
+
+impl<I: Idx, T: Clone> ToOwned for IndexSlice<I, T> {
+ type Owned = IndexVec<I, T>;
+
+ fn to_owned(&self) -> IndexVec<I, T> {
+ IndexVec::from_raw(self.raw.to_owned())
+ }
+
+ fn clone_into(&self, target: &mut IndexVec<I, T>) {
+ self.raw.clone_into(&mut target.raw)
+ }
+}
+
+impl<I: Idx, T> Default for &IndexSlice<I, T> {
+ #[inline]
+ fn default() -> Self {
+ IndexSlice::from_raw(Default::default())
+ }
+}
+
+impl<I: Idx, T> Default for &mut IndexSlice<I, T> {
+ #[inline]
+ fn default() -> Self {
+ IndexSlice::from_raw_mut(Default::default())
+ }
+}
+
+// Whether `IndexSlice` is `Send` depends only on the data,
+// not the phantom data.
+unsafe impl<I: Idx, T> Send for IndexSlice<I, T> where T: Send {}
diff --git a/compiler/rustc_index/src/vec.rs b/compiler/rustc_index/src/vec.rs
index ae2f52c51..99e72e49f 100644
--- a/compiler/rustc_index/src/vec.rs
+++ b/compiler/rustc_index/src/vec.rs
@@ -3,55 +3,13 @@ use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::borrow::{Borrow, BorrowMut};
use std::fmt;
-use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
-use std::ops::{Deref, DerefMut, Index, IndexMut, RangeBounds};
+use std::ops::{Deref, DerefMut, RangeBounds};
use std::slice;
use std::vec;
-/// Represents some newtyped `usize` wrapper.
-///
-/// Purpose: avoid mixing indexes for different bitvector domains.
-pub trait Idx: Copy + 'static + Eq + PartialEq + Debug + Hash {
- fn new(idx: usize) -> Self;
-
- fn index(self) -> usize;
-
- #[inline]
- fn increment_by(&mut self, amount: usize) {
- *self = self.plus(amount);
- }
-
- #[inline]
- #[must_use = "Use `increment_by` if you wanted to update the index in-place"]
- fn plus(self, amount: usize) -> Self {
- Self::new(self.index() + amount)
- }
-}
-
-impl Idx for usize {
- #[inline]
- fn new(idx: usize) -> Self {
- idx
- }
- #[inline]
- fn index(self) -> usize {
- self
- }
-}
-
-impl Idx for u32 {
- #[inline]
- fn new(idx: usize) -> Self {
- assert!(idx <= u32::MAX as usize);
- idx as u32
- }
- #[inline]
- fn index(self) -> usize {
- self as usize
- }
-}
+use crate::{Idx, IndexSlice};
/// An owned contiguous collection of `T`s, indexed by `I` rather than by `usize`.
///
@@ -66,68 +24,20 @@ pub struct IndexVec<I: Idx, T> {
_marker: PhantomData<fn(&I)>,
}
-/// A view into contiguous `T`s, indexed by `I` rather than by `usize`.
-///
-/// One common pattern you'll see is code that uses [`IndexVec::from_elem`]
-/// to create the storage needed for a particular "universe" (aka the set of all
-/// the possible keys that need an associated value) then passes that working
-/// area as `&mut IndexSlice<I, T>` to clarify that nothing will be added nor
-/// removed during processing (and, as a bonus, to chase fewer pointers).
-#[derive(PartialEq, Eq, Hash)]
-#[repr(transparent)]
-pub struct IndexSlice<I: Idx, T> {
- _marker: PhantomData<fn(&I)>,
- pub raw: [T],
-}
-
-// Whether `IndexVec` is `Send` depends only on the data,
-// not the phantom data.
-unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
-
-// Whether `IndexSlice` is `Send` depends only on the data,
-// not the phantom data.
-unsafe impl<I: Idx, T> Send for IndexSlice<I, T> where T: Send {}
-
-#[cfg(feature = "rustc_serialize")]
-impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> {
- fn encode(&self, s: &mut S) {
- Encodable::encode(&self.raw, s);
- }
-}
-
-#[cfg(feature = "rustc_serialize")]
-impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> {
- fn decode(d: &mut D) -> Self {
- IndexVec { raw: Decodable::decode(d), _marker: PhantomData }
- }
-}
-
-impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.raw, fmt)
- }
-}
-
-impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexSlice<I, T> {
- fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
- fmt::Debug::fmt(&self.raw, fmt)
- }
-}
-
impl<I: Idx, T> IndexVec<I, T> {
#[inline]
- pub fn new() -> Self {
- IndexVec { raw: Vec::new(), _marker: PhantomData }
+ pub const fn new() -> Self {
+ IndexVec::from_raw(Vec::new())
}
#[inline]
- pub fn from_raw(raw: Vec<T>) -> Self {
+ pub const fn from_raw(raw: Vec<T>) -> Self {
IndexVec { raw, _marker: PhantomData }
}
#[inline]
pub fn with_capacity(capacity: usize) -> Self {
- IndexVec { raw: Vec::with_capacity(capacity), _marker: PhantomData }
+ IndexVec::from_raw(Vec::with_capacity(capacity))
}
/// Creates a new vector with a copy of `elem` for each index in `universe`.
@@ -146,7 +56,7 @@ impl<I: Idx, T> IndexVec<I, T> {
where
T: Clone,
{
- IndexVec { raw: vec![elem; universe.len()], _marker: PhantomData }
+ IndexVec::from_raw(vec![elem; universe.len()])
}
#[inline]
@@ -154,7 +64,7 @@ impl<I: Idx, T> IndexVec<I, T> {
where
T: Clone,
{
- IndexVec { raw: vec![elem; n], _marker: PhantomData }
+ IndexVec::from_raw(vec![elem; n])
}
/// Create an `IndexVec` with `n` elements, where the value of each
@@ -162,8 +72,7 @@ impl<I: Idx, T> IndexVec<I, T> {
/// be allocated only once, with a capacity of at least `n`.)
#[inline]
pub fn from_fn_n(func: impl FnMut(I) -> T, n: usize) -> Self {
- let indices = (0..n).map(I::new);
- Self::from_raw(indices.map(func).collect())
+ IndexVec::from_raw((0..n).map(I::new).map(func).collect())
}
#[inline]
@@ -178,7 +87,7 @@ impl<I: Idx, T> IndexVec<I, T> {
#[inline]
pub fn push(&mut self, d: T) -> I {
- let idx = I::new(self.len());
+ let idx = self.next_index();
self.raw.push(d);
idx
}
@@ -229,216 +138,37 @@ impl<I: Idx, T> IndexVec<I, T> {
}
pub fn convert_index_type<Ix: Idx>(self) -> IndexVec<Ix, T> {
- IndexVec { raw: self.raw, _marker: PhantomData }
+ IndexVec::from_raw(self.raw)
}
/// Grows the index vector so that it contains an entry for
/// `elem`; if that is already true, then has no
/// effect. Otherwise, inserts new values as needed by invoking
/// `fill_value`.
+ ///
+ /// Returns a reference to the `elem` entry.
#[inline]
- pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+ pub fn ensure_contains_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) -> &mut T {
let min_new_len = elem.index() + 1;
if self.len() < min_new_len {
self.raw.resize_with(min_new_len, fill_value);
}
- }
-
- #[inline]
- pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
- let min_new_len = elem.index() + 1;
- self.raw.resize_with(min_new_len, fill_value);
- }
-}
-
-impl<I: Idx, T> Deref for IndexVec<I, T> {
- type Target = IndexSlice<I, T>;
-
- #[inline]
- fn deref(&self) -> &Self::Target {
- self.as_slice()
- }
-}
-
-impl<I: Idx, T> DerefMut for IndexVec<I, T> {
- #[inline]
- fn deref_mut(&mut self) -> &mut Self::Target {
- self.as_mut_slice()
- }
-}
-
-impl<I: Idx, T> Borrow<IndexSlice<I, T>> for IndexVec<I, T> {
- fn borrow(&self) -> &IndexSlice<I, T> {
- self
- }
-}
-
-impl<I: Idx, T> BorrowMut<IndexSlice<I, T>> for IndexVec<I, T> {
- fn borrow_mut(&mut self) -> &mut IndexSlice<I, T> {
- self
- }
-}
-
-impl<I: Idx, T: Clone> ToOwned for IndexSlice<I, T> {
- type Owned = IndexVec<I, T>;
-
- fn to_owned(&self) -> IndexVec<I, T> {
- IndexVec::from_raw(self.raw.to_owned())
- }
-
- fn clone_into(&self, target: &mut IndexVec<I, T>) {
- self.raw.clone_into(&mut target.raw)
- }
-}
-
-impl<I: Idx, T> IndexSlice<I, T> {
- #[inline]
- pub fn empty() -> &'static Self {
- Default::default()
- }
-
- #[inline]
- pub fn from_raw(raw: &[T]) -> &Self {
- let ptr: *const [T] = raw;
- // SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
- unsafe { &*(ptr as *const Self) }
- }
-
- #[inline]
- pub fn from_raw_mut(raw: &mut [T]) -> &mut Self {
- let ptr: *mut [T] = raw;
- // SAFETY: `IndexSlice` is `repr(transparent)` over a normal slice
- unsafe { &mut *(ptr as *mut Self) }
- }
-
- #[inline]
- pub fn len(&self) -> usize {
- self.raw.len()
- }
-
- /// Gives the next index that will be assigned when `push` is called.
- ///
- /// Manual bounds checks can be done using `idx < slice.next_index()`
- /// (as opposed to `idx.index() < slice.len()`).
- #[inline]
- pub fn next_index(&self) -> I {
- I::new(self.len())
- }
-
- #[inline]
- pub fn is_empty(&self) -> bool {
- self.raw.is_empty()
- }
-
- #[inline]
- pub fn iter(&self) -> slice::Iter<'_, T> {
- self.raw.iter()
- }
- #[inline]
- pub fn iter_enumerated(
- &self,
- ) -> impl DoubleEndedIterator<Item = (I, &T)> + ExactSizeIterator + '_ {
- self.raw.iter().enumerate().map(|(n, t)| (I::new(n), t))
- }
-
- #[inline]
- pub fn indices(
- &self,
- ) -> impl DoubleEndedIterator<Item = I> + ExactSizeIterator + Clone + 'static {
- (0..self.len()).map(|n| I::new(n))
- }
-
- #[inline]
- pub fn iter_mut(&mut self) -> slice::IterMut<'_, T> {
- self.raw.iter_mut()
+ &mut self[elem]
}
#[inline]
- pub fn iter_enumerated_mut(
- &mut self,
- ) -> impl DoubleEndedIterator<Item = (I, &mut T)> + ExactSizeIterator + '_ {
- self.raw.iter_mut().enumerate().map(|(n, t)| (I::new(n), t))
- }
-
- #[inline]
- pub fn last_index(&self) -> Option<I> {
- self.len().checked_sub(1).map(I::new)
- }
-
- #[inline]
- pub fn swap(&mut self, a: I, b: I) {
- self.raw.swap(a.index(), b.index())
- }
-
- #[inline]
- pub fn get(&self, index: I) -> Option<&T> {
- self.raw.get(index.index())
- }
-
- #[inline]
- pub fn get_mut(&mut self, index: I) -> Option<&mut T> {
- self.raw.get_mut(index.index())
- }
-
- /// Returns mutable references to two distinct elements, `a` and `b`.
- ///
- /// Panics if `a == b`.
- #[inline]
- pub fn pick2_mut(&mut self, a: I, b: I) -> (&mut T, &mut T) {
- let (ai, bi) = (a.index(), b.index());
- assert!(ai != bi);
-
- if ai < bi {
- let (c1, c2) = self.raw.split_at_mut(bi);
- (&mut c1[ai], &mut c2[0])
- } else {
- let (c2, c1) = self.pick2_mut(b, a);
- (c1, c2)
- }
+ pub fn resize(&mut self, new_len: usize, value: T)
+ where
+ T: Clone,
+ {
+ self.raw.resize(new_len, value)
}
- /// Returns mutable references to three distinct elements.
- ///
- /// Panics if the elements are not distinct.
#[inline]
- pub fn pick3_mut(&mut self, a: I, b: I, c: I) -> (&mut T, &mut T, &mut T) {
- let (ai, bi, ci) = (a.index(), b.index(), c.index());
- assert!(ai != bi && bi != ci && ci != ai);
- let len = self.raw.len();
- assert!(ai < len && bi < len && ci < len);
- let ptr = self.raw.as_mut_ptr();
- unsafe { (&mut *ptr.add(ai), &mut *ptr.add(bi), &mut *ptr.add(ci)) }
- }
-}
-
-impl<I: Idx, J: Idx> IndexSlice<I, J> {
- /// Invert a bijective mapping, i.e. `invert(map)[y] = x` if `map[x] = y`,
- /// assuming the values in `self` are a permutation of `0..self.len()`.
- ///
- /// This is used to go between `memory_index` (source field order to memory order)
- /// and `inverse_memory_index` (memory order to source field order).
- /// See also `FieldsShape::Arbitrary::memory_index` for more details.
- // FIXME(eddyb) build a better abstraction for permutations, if possible.
- pub fn invert_bijective_mapping(&self) -> IndexVec<J, I> {
- debug_assert_eq!(
- self.iter().map(|x| x.index() as u128).sum::<u128>(),
- (0..self.len() as u128).sum::<u128>(),
- "The values aren't 0..N in input {self:?}",
- );
-
- let mut inverse = IndexVec::from_elem_n(Idx::new(0), self.len());
- for (i1, &i2) in self.iter_enumerated() {
- inverse[i2] = i1;
- }
-
- debug_assert_eq!(
- inverse.iter().map(|x| x.index() as u128).sum::<u128>(),
- (0..inverse.len() as u128).sum::<u128>(),
- "The values aren't 0..N in result {self:?}",
- );
-
- inverse
+ pub fn resize_to_elem(&mut self, elem: I, fill_value: impl FnMut() -> T) {
+ let min_new_len = elem.index() + 1;
+ self.raw.resize_with(min_new_len, fill_value);
}
}
@@ -446,74 +176,51 @@ impl<I: Idx, J: Idx> IndexSlice<I, J> {
impl<I: Idx, T> IndexVec<I, Option<T>> {
#[inline]
pub fn insert(&mut self, index: I, value: T) -> Option<T> {
- self.ensure_contains_elem(index, || None);
- self[index].replace(value)
+ self.ensure_contains_elem(index, || None).replace(value)
}
#[inline]
pub fn get_or_insert_with(&mut self, index: I, value: impl FnOnce() -> T) -> &mut T {
- self.ensure_contains_elem(index, || None);
- self[index].get_or_insert_with(value)
+ self.ensure_contains_elem(index, || None).get_or_insert_with(value)
}
#[inline]
pub fn remove(&mut self, index: I) -> Option<T> {
- self.ensure_contains_elem(index, || None);
- self[index].take()
- }
-}
-
-impl<I: Idx, T: Clone> IndexVec<I, T> {
- #[inline]
- pub fn resize(&mut self, new_len: usize, value: T) {
- self.raw.resize(new_len, value)
+ self.get_mut(index)?.take()
}
}
-impl<I: Idx, T: Ord> IndexSlice<I, T> {
- #[inline]
- pub fn binary_search(&self, value: &T) -> Result<I, I> {
- match self.raw.binary_search(value) {
- Ok(i) => Ok(Idx::new(i)),
- Err(i) => Err(Idx::new(i)),
- }
+impl<I: Idx, T: fmt::Debug> fmt::Debug for IndexVec<I, T> {
+ fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::Debug::fmt(&self.raw, fmt)
}
}
-impl<I: Idx, T> Index<I> for IndexSlice<I, T> {
- type Output = T;
-
- #[inline]
- fn index(&self, index: I) -> &T {
- &self.raw[index.index()]
- }
-}
+impl<I: Idx, T> Deref for IndexVec<I, T> {
+ type Target = IndexSlice<I, T>;
-impl<I: Idx, T> IndexMut<I> for IndexSlice<I, T> {
#[inline]
- fn index_mut(&mut self, index: I) -> &mut T {
- &mut self.raw[index.index()]
+ fn deref(&self) -> &Self::Target {
+ self.as_slice()
}
}
-impl<I: Idx, T> Default for IndexVec<I, T> {
+impl<I: Idx, T> DerefMut for IndexVec<I, T> {
#[inline]
- fn default() -> Self {
- Self::new()
+ fn deref_mut(&mut self) -> &mut Self::Target {
+ self.as_mut_slice()
}
}
-impl<I: Idx, T> Default for &IndexSlice<I, T> {
- #[inline]
- fn default() -> Self {
- IndexSlice::from_raw(Default::default())
+impl<I: Idx, T> Borrow<IndexSlice<I, T>> for IndexVec<I, T> {
+ fn borrow(&self) -> &IndexSlice<I, T> {
+ self
}
}
-impl<I: Idx, T> Default for &mut IndexSlice<I, T> {
- #[inline]
- fn default() -> Self {
- IndexSlice::from_raw_mut(Default::default())
+impl<I: Idx, T> BorrowMut<IndexSlice<I, T>> for IndexVec<I, T> {
+ fn borrow_mut(&mut self) -> &mut IndexSlice<I, T> {
+ self
}
}
@@ -542,14 +249,7 @@ impl<I: Idx, T> FromIterator<T> for IndexVec<I, T> {
where
J: IntoIterator<Item = T>,
{
- IndexVec { raw: FromIterator::from_iter(iter), _marker: PhantomData }
- }
-}
-
-impl<I: Idx, T, const N: usize> From<[T; N]> for IndexVec<I, T> {
- #[inline]
- fn from(array: [T; N]) -> Self {
- IndexVec::from_raw(array.into())
+ IndexVec::from_raw(Vec::from_iter(iter))
}
}
@@ -569,7 +269,7 @@ impl<'a, I: Idx, T> IntoIterator for &'a IndexVec<I, T> {
#[inline]
fn into_iter(self) -> slice::Iter<'a, T> {
- self.raw.iter()
+ self.iter()
}
}
@@ -579,29 +279,41 @@ impl<'a, I: Idx, T> IntoIterator for &'a mut IndexVec<I, T> {
#[inline]
fn into_iter(self) -> slice::IterMut<'a, T> {
- self.raw.iter_mut()
+ self.iter_mut()
}
}
-impl<'a, I: Idx, T> IntoIterator for &'a IndexSlice<I, T> {
- type Item = &'a T;
- type IntoIter = slice::Iter<'a, T>;
+impl<I: Idx, T> Default for IndexVec<I, T> {
+ #[inline]
+ fn default() -> Self {
+ IndexVec::new()
+ }
+}
+impl<I: Idx, T, const N: usize> From<[T; N]> for IndexVec<I, T> {
#[inline]
- fn into_iter(self) -> slice::Iter<'a, T> {
- self.raw.iter()
+ fn from(array: [T; N]) -> Self {
+ IndexVec::from_raw(array.into())
}
}
-impl<'a, I: Idx, T> IntoIterator for &'a mut IndexSlice<I, T> {
- type Item = &'a mut T;
- type IntoIter = slice::IterMut<'a, T>;
+#[cfg(feature = "rustc_serialize")]
+impl<S: Encoder, I: Idx, T: Encodable<S>> Encodable<S> for IndexVec<I, T> {
+ fn encode(&self, s: &mut S) {
+ Encodable::encode(&self.raw, s);
+ }
+}
- #[inline]
- fn into_iter(self) -> slice::IterMut<'a, T> {
- self.raw.iter_mut()
+#[cfg(feature = "rustc_serialize")]
+impl<D: Decoder, I: Idx, T: Decodable<D>> Decodable<D> for IndexVec<I, T> {
+ fn decode(d: &mut D) -> Self {
+ IndexVec::from_raw(Vec::<T>::decode(d))
}
}
+// Whether `IndexVec` is `Send` depends only on the data,
+// not the phantom data.
+unsafe impl<I: Idx, T> Send for IndexVec<I, T> where T: Send {}
+
#[cfg(test)]
mod tests;
diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml
index 02ac83a5e..9dd5868ad 100644
--- a/compiler/rustc_infer/Cargo.toml
+++ b/compiler/rustc_infer/Cargo.toml
@@ -12,6 +12,7 @@ rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
diff --git a/compiler/rustc_infer/messages.ftl b/compiler/rustc_infer/messages.ftl
index c8998ea91..f44c4a7c1 100644
--- a/compiler/rustc_infer/messages.ftl
+++ b/compiler/rustc_infer/messages.ftl
@@ -1,285 +1,72 @@
-infer_opaque_hidden_type =
- opaque type's hidden type cannot be another opaque type from the same scope
- .label = one of the two opaque types used here has to be outside its defining scope
- .opaque_type = opaque type whose hidden type is being assigned
- .hidden_type = opaque type being used as hidden type
-
-infer_type_annotations_needed = {$source_kind ->
- [closure] type annotations needed for the closure `{$source_name}`
- [normal] type annotations needed for `{$source_name}`
- *[other] type annotations needed
-}
- .label = type must be known at this point
-
-infer_label_bad = {$bad_kind ->
- *[other] cannot infer type
- [more_info] cannot infer {$prefix_kind ->
- *[type] type for {$prefix}
- [const_with_param] the value of const parameter
- [const] the value of the constant
- } `{$name}`{$has_parent ->
- [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
- *[false] {""}
- }
-}
-
-infer_source_kind_subdiag_let = {$kind ->
- [with_pattern] consider giving `{$name}` an explicit type
- [closure] consider giving this closure parameter an explicit type
- *[other] consider giving this pattern a type
-}{$x_kind ->
- [has_name] , where the {$prefix_kind ->
- *[type] type for {$prefix}
- [const_with_param] value of const parameter
- [const] value of the constant
- } `{$arg_name}` is specified
- [underscore] , where the placeholders `_` are specified
- *[empty] {""}
-}
-
-infer_source_kind_subdiag_generic_label =
- cannot infer {$is_type ->
- [true] type
- *[false] the value
- } of the {$is_type ->
- [true] type
- *[false] const
- } {$parent_exists ->
- [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
- *[false] parameter {$param_name}
- }
-
-infer_source_kind_subdiag_generic_suggestion =
- consider specifying the generic {$arg_count ->
- [one] argument
- *[other] arguments
- }
-
-infer_source_kind_fully_qualified =
- try using a fully qualified path to specify the expected types
-
-infer_source_kind_closure_return =
- try giving this closure an explicit return type
-
-# generator_kind may need to be translated
-infer_need_type_info_in_generator =
- type inside {$generator_kind ->
- [async_block] `async` block
- [async_closure] `async` closure
- [async_fn] `async fn` body
- *[generator] generator
- } must be known in this context
-
-
-infer_subtype = ...so that the {$requirement ->
- [method_compat] method type is compatible with trait
- [type_compat] associated type is compatible with trait
- [const_compat] const is compatible with trait
- [expr_assignable] expression is assignable
- [if_else_different] `if` and `else` have incompatible types
- [no_else] `if` missing an `else` returns `()`
- [fn_main_correct_type] `main` function has the correct type
- [fn_start_correct_type] `#[start]` function has the correct type
- [intristic_correct_type] intrinsic has the correct type
- [method_correct_type] method receiver has the correct type
- *[other] types are compatible
-}
-infer_subtype_2 = ...so that {$requirement ->
- [method_compat] method type is compatible with trait
- [type_compat] associated type is compatible with trait
- [const_compat] const is compatible with trait
- [expr_assignable] expression is assignable
- [if_else_different] `if` and `else` have incompatible types
- [no_else] `if` missing an `else` returns `()`
- [fn_main_correct_type] `main` function has the correct type
- [fn_start_correct_type] `#[start]` function has the correct type
- [intristic_correct_type] intrinsic has the correct type
- [method_correct_type] method receiver has the correct type
- *[other] types are compatible
-}
-
-infer_reborrow = ...so that reference does not outlive borrowed content
-infer_reborrow_upvar = ...so that closure can access `{$name}`
-infer_relate_object_bound = ...so that it can be closed over into an object
-infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
-infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
- [true] ...
+infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
-infer_relate_param_bound_2 = ...that is required by this bound
-infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
-infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
-infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
-
-infer_nothing = {""}
-
-infer_lifetime_mismatch = lifetime mismatch
-
-infer_declared_different = this parameter and the return type are declared with different lifetimes...
-infer_data_returned = ...but data{$label_var1_exists ->
- [true] {" "}from `{$label_var1}`
- *[false] {""}
-} is returned here
-
-infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
-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}`
- *[false] -> {""}
-} flows{$label_var2_exists ->
- [true] {" "}into `{$label_var2}`
- *[false] -> {""}
-} here
-
-infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
- [true] {" "}and update trait if needed
+infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
*[false] {""}
}
-infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
-
-infer_region_explanation = {$pref_kind ->
- *[should_not_happen] [{$pref_kind}]
- [ref_valid_for] ...the reference is valid for
- [content_valid_for] ...but the borrowed content is only valid for
- [type_obj_valid_for] object type is valid for
- [source_pointer_valid_for] source pointer is only valid for
- [type_satisfy] type must satisfy
- [type_outlive] type must outlive
- [lf_param_instantiated_with] lifetime parameter instantiated with
- [lf_param_must_outlive] but lifetime parameter must outlive
- [lf_instantiated_with] lifetime instantiated with
- [lf_must_outlive] but lifetime must outlive
- [pointer_valid_for] the pointer is valid for
- [data_valid_for] but the referenced data is only valid for
- [empty] {""}
-}{$pref_kind ->
- [empty] {""}
- *[other] {" "}
-}{$desc_kind ->
- *[should_not_happen] [{$desc_kind}]
- [restatic] the static lifetime
- [revar] lifetime {$desc_arg}
- [as_defined] the lifetime `{$desc_arg}` as defined here
- [as_defined_anon] the anonymous lifetime as defined here
- [defined_here] the anonymous lifetime defined here
- [defined_here_reg] the lifetime `{$desc_arg}` as defined here
-}{$suff_kind ->
- *[should_not_happen] [{$suff_kind}]
- [empty]{""}
- [continues] ...
- [req_by_binding] {" "}as required by this binding
+infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
+ [true] , for some specific lifetime `'{$lifetime}`
+ *[false] {""}
}
-infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
-infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
-infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
-infer_lf_bound_not_satisfied = lifetime bound not satisfied
-infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
-infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
-
-infer_mismatched_static_lifetime = incompatible lifetime on type
-infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
-infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
-infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
-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`
-
-infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
- .label = lifetime `{$named}` required
-
-infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
- .label = lifetime `{$named}` required
-
-infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
-
-infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
-
-infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
- [true] ...
- *[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
+infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
+}`{$ty_or_sig}` must implement `{$trait_path}`
+
+infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
-infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
+}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
infer_actual_impl_expl_expected_passive_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
- [true] ...
- *[false] {""}
-}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
infer_actual_impl_expl_expected_passive_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`
-infer_actual_impl_expl_expected_other_two = {$leading_ellipsis ->
+infer_actual_impl_expl_expected_passive_some = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
-infer_actual_impl_expl_expected_other_any = {$leading_ellipsis ->
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_passive_two = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_some = {$leading_ellipsis ->
+}`{$trait_path}` would have to be implemented for the type `{$ty_or_sig}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_actual_impl_expl_expected_signature_any = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
-infer_actual_impl_expl_expected_other_nothing = {$leading_ellipsis ->
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_nothing = {$leading_ellipsis ->
[true] ...
*[false] {""}
-}`{$ty_or_sig}` must implement `{$trait_path}`
-
-infer_actual_impl_expl_but_actually_implements_trait = ...but it actually implements `{$trait_path}`{$has_lifetime ->
- [true] , for some specific lifetime `'{$lifetime}`
- *[false] {""}
-}
-infer_actual_impl_expl_but_actually_implemented_for_ty = ...but `{$trait_path}` is actually implemented for the type `{$ty}`{$has_lifetime ->
- [true] , for some specific lifetime `'{$lifetime}`
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`
+infer_actual_impl_expl_expected_signature_some = {$leading_ellipsis ->
+ [true] ...
*[false] {""}
-}
-infer_actual_impl_expl_but_actually_ty_implements = ...but `{$ty}` actually implements `{$trait_path}`{$has_lifetime ->
- [true] , for some specific lifetime `'{$lifetime}`
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for some specific lifetime `'{$lifetime_1}`...
+infer_actual_impl_expl_expected_signature_two = {$leading_ellipsis ->
+ [true] ...
*[false] {""}
-}
-
-infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
- .label_satisfy = doesn't satisfy where-clause
- .label_where = due to a where-clause on `{$def_id}`...
- .label_dup = implementation of `{$trait_def_id}` is not general enough
-
-infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
- .found = found `{$found}`
- .expected = expected `{$expected}`
- .expected_found = expected signature `{$expected}`
- {" "}found signature `{$found}`
-
-infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
-infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
-infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+}closure with signature `{$ty_or_sig}` must implement `{$trait_path}`, for any two lifetimes `'{$lifetime_1}` and `'{$lifetime_2}`...
+infer_ascribe_user_type_prove_predicate = ...so that the where clause holds
-infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
-infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
-infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
-infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+infer_await_both_futures = consider `await`ing on both `Future`s
+infer_await_future = consider `await`ing on the `Future`
+infer_await_note = calling an async function returns a future
+infer_borrowed_too_long = a value of type `{$ty}` is borrowed for too long
infer_but_calling_introduces = {$has_param_name ->
[true] `{$param_name}`
*[false] `fn` parameter
@@ -314,6 +101,77 @@ infer_but_needs_to_satisfy = {$has_param_name ->
.used_here = ...is used here...
.introduced_by_bound = `'static` lifetime requirement introduced by this bound
+infer_compare_impl_item_obligation = ...so that the definition in impl matches the definition from the trait
+infer_consider_specifying_length = consider specifying the actual array length
+infer_data_flows = ...but data{$label_var1_exists ->
+ [true] {" "}from `{$label_var1}`
+ *[false] -> {""}
+} flows{$label_var2_exists ->
+ [true] {" "}into `{$label_var2}`
+ *[false] -> {""}
+} here
+
+infer_data_lifetime_flow = ...but data with one lifetime flows into the other here
+infer_data_returned = ...but data{$label_var1_exists ->
+ [true] {" "}from `{$label_var1}`
+ *[false] {""}
+} is returned here
+
+infer_declared_different = this parameter and the return type are declared with different lifetimes...
+infer_declared_multiple = this type is declared with multiple lifetimes...
+infer_does_not_outlive_static_from_impl = ...does not necessarily outlive the static lifetime introduced by the compatible `impl`
+infer_dtcs_has_lifetime_req_label = this has an implicit `'static` lifetime requirement
+infer_dtcs_has_req_note = the used `impl` has a `'static` requirement
+infer_dtcs_introduces_requirement = calling this method introduces the `impl`'s `'static` requirement
+infer_dtcs_suggestion = consider relaxing the implicit `'static` requirement
+
+infer_explicit_lifetime_required_sugg_with_ident = add explicit lifetime `{$named}` to the type of `{$simple_ident}`
+
+infer_explicit_lifetime_required_sugg_with_param_type = add explicit lifetime `{$named}` to type
+
+infer_explicit_lifetime_required_with_ident = explicit lifetime required in the type of `{$simple_ident}`
+ .label = lifetime `{$named}` required
+
+infer_explicit_lifetime_required_with_param_type = explicit lifetime required in parameter type
+ .label = lifetime `{$named}` required
+
+infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+
+infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
+infer_fps_cast = consider casting to a fn pointer
+infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+
+infer_fps_items_are_distinct = fn items are distinct from fn pointers
+infer_fps_remove_ref = consider removing the reference
+infer_fps_use_ref = consider using a reference
+infer_fulfill_req_lifetime = the type `{$ty}` does not fulfill the required lifetime
+infer_implicit_static_lifetime_note = this has an implicit `'static` lifetime requirement
+infer_implicit_static_lifetime_suggestion = consider relaxing the implicit `'static` requirement
+infer_label_bad = {$bad_kind ->
+ *[other] cannot infer type
+ [more_info] cannot infer {$prefix_kind ->
+ *[type] type for {$prefix}
+ [const_with_param] the value of const parameter
+ [const] the value of the constant
+ } `{$name}`{$has_parent ->
+ [true] {" "}declared on the {$parent_prefix} `{$parent_name}`
+ *[false] {""}
+ }
+}
+
+infer_lf_bound_not_satisfied = lifetime bound not satisfied
+infer_lifetime_mismatch = lifetime mismatch
+
+infer_lifetime_param_suggestion = consider introducing a named lifetime parameter{$is_impl ->
+ [true] {" "}and update trait if needed
+ *[false] {""}
+}
+infer_lifetime_param_suggestion_elided = each elided lifetime in input position becomes a distinct lifetime
+
+infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
+infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
+infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
+infer_mismatched_static_lifetime = incompatible lifetime on type
infer_more_targeted = {$has_param_name ->
[true] `{$param_name}`
*[false] `fn` parameter
@@ -322,72 +180,215 @@ infer_more_targeted = {$has_param_name ->
*[false] an anonymous lifetime `'_`
} but calling `{$ident}` introduces an implicit `'static` lifetime requirement
-infer_ril_introduced_here = `'static` requirement introduced here
-infer_ril_introduced_by = requirement introduced by this return type
-infer_ril_because_of = because of this returned expression
-infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
+infer_msl_introduces_static = introduces a `'static` lifetime requirement
+infer_msl_trait_note = this has an implicit `'static` lifetime requirement
+infer_msl_trait_sugg = consider relaxing the implicit `'static` requirement
+infer_msl_unmet_req = because this has an unmet lifetime requirement
+infer_need_type_info_in_generator =
+ type inside {$generator_kind ->
+ [async_block] `async` block
+ [async_closure] `async` closure
+ [async_fn] `async fn` body
+ *[generator] generator
+ } must be known in this context
-infer_where_remove = remove the `where` clause
-infer_where_copy_predicates = copy the `where` clause predicates from the trait
-infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
-infer_srs_remove = consider removing this semicolon
-infer_srs_add = consider returning the local binding `{$ident}`
-infer_srs_add_one = consider returning one of these bindings
+infer_nothing = {""}
-infer_await_both_futures = consider `await`ing on both `Future`s
-infer_await_future = consider `await`ing on the `Future`
-infer_await_note = calling an async function returns a future
+infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
+infer_oc_closure_selfref = closure/generator type that references itself
+infer_oc_const_compat = const not compatible with trait
+infer_oc_fn_main_correct_type = `main` function has wrong type
+infer_oc_fn_start_correct_type = `#[start]` function has wrong type
+infer_oc_generic = mismatched types
+
+infer_oc_if_else_different = `if` and `else` have incompatible types
+infer_oc_intrinsic_correct_type = intrinsic has wrong type
+infer_oc_match_compat = `match` arms have incompatible types
+infer_oc_method_compat = method not compatible with trait
+infer_oc_method_correct_type = mismatched `self` parameter type
+infer_oc_no_diverge = `else` clause of `let...else` does not diverge
+infer_oc_no_else = `if` may be missing an `else` clause
+infer_oc_try_compat = `?` operator has incompatible types
+infer_oc_type_compat = type not compatible with trait
+infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
+ .label = opaque type defined here
+
+infer_opaque_hidden_type =
+ opaque type's hidden type cannot be another opaque type from the same scope
+ .label = one of the two opaque types used here has to be outside its defining scope
+ .opaque_type = opaque type whose hidden type is being assigned
+ .hidden_type = opaque type being used as hidden type
+infer_outlives_bound = lifetime of the source pointer does not outlive lifetime bound of the object type
+infer_outlives_content = lifetime of reference outlives lifetime of borrowed content...
infer_prlf_defined_with_sub = the lifetime `{$sub_symbol}` defined here...
infer_prlf_defined_without_sub = the lifetime defined here...
-infer_prlf_must_oultive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
-infer_prlf_must_oultive_without_sup = ...must outlive the lifetime defined here
infer_prlf_known_limitation = 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)
-infer_opaque_captures_lifetime = hidden type for `{$opaque_ty}` captures lifetime that does not appear in bounds
- .label = opaque type defined here
+infer_prlf_must_outlive_with_sup = ...must outlive the lifetime `{$sup_symbol}` defined here
+infer_prlf_must_outlive_without_sup = ...must outlive the lifetime defined here
+infer_reborrow = ...so that reference does not outlive borrowed content
+infer_reborrow_upvar = ...so that closure can access `{$name}`
+infer_ref_longer_than_data = in type `{$ty}`, reference has a longer lifetime than the data it references
-infer_fps_use_ref = consider using a reference
-infer_fps_remove_ref = consider removing the reference
-infer_fps_cast = consider casting to a fn pointer
-infer_fps_items_are_distinct = fn items are distinct from fn pointers
-infer_fps_cast_both = consider casting both fn items to fn pointers using `as {$expected_sig}`
+infer_reference_outlives_referent = ...so that the reference type `{$name}` does not outlive the data it points at
+infer_region_explanation = {$pref_kind ->
+ *[should_not_happen] [{$pref_kind}]
+ [ref_valid_for] ...the reference is valid for
+ [content_valid_for] ...but the borrowed content is only valid for
+ [type_obj_valid_for] object type is valid for
+ [source_pointer_valid_for] source pointer is only valid for
+ [type_satisfy] type must satisfy
+ [type_outlive] type must outlive
+ [lf_param_instantiated_with] lifetime parameter instantiated with
+ [lf_param_must_outlive] but lifetime parameter must outlive
+ [lf_instantiated_with] lifetime instantiated with
+ [lf_must_outlive] but lifetime must outlive
+ [pointer_valid_for] the pointer is valid for
+ [data_valid_for] but the referenced data is only valid for
+ [empty] {""}
+}{$pref_kind ->
+ [empty] {""}
+ *[other] {" "}
+}{$desc_kind ->
+ *[should_not_happen] [{$desc_kind}]
+ [restatic] the static lifetime
+ [revar] lifetime {$desc_arg}
+ [as_defined] the lifetime `{$desc_arg}` as defined here
+ [as_defined_anon] the anonymous lifetime as defined here
+ [defined_here] the anonymous lifetime defined here
+ [defined_here_reg] the lifetime `{$desc_arg}` as defined here
+}{$suff_kind ->
+ *[should_not_happen] [{$suff_kind}]
+ [empty]{""}
+ [continues] ...
+ [req_by_binding] {" "}as required by this binding
+}
-infer_fn_uniq_types = different fn items have unique types, even if their signatures are the same
-infer_fn_consider_casting = consider casting the fn item to a fn pointer: `{$casting}`
+infer_relate_object_bound = ...so that it can be closed over into an object
+infer_relate_param_bound = ...so that the type `{$name}` will meet its required lifetime bounds{$continues ->
+ [true] ...
+ *[false] {""}
+}
+infer_relate_param_bound_2 = ...that is required by this bound
+infer_relate_region_param_bound = ...so that the declared lifetime parameter bounds are satisfied
+infer_ril_because_of = because of this returned expression
+infer_ril_introduced_by = requirement introduced by this return type
+infer_ril_introduced_here = `'static` requirement introduced here
+infer_ril_static_introduced_by = "`'static` lifetime requirement introduced by the return type
infer_sarwa_option = you can convert from `&Option<T>` to `Option<&T>` using `.as_ref()`
infer_sarwa_result = you can convert from `&Result<T, E>` to `Result<&T, &E>` using `.as_ref()`
-infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
+infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions
infer_sbfrit_change_return_type = you could change the return type to be a boxed trait object
-infer_sbfrit_box_return_expr = if you change the return type to expect trait objects, box the returned expressions
+infer_source_kind_closure_return =
+ try giving this closure an explicit return type
-infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
+# generator_kind may need to be translated
+infer_source_kind_fully_qualified =
+ try using a fully qualified path to specify the expected types
+
+infer_source_kind_subdiag_generic_label =
+ cannot infer {$is_type ->
+ [true] type
+ *[false] the value
+ } of the {$is_type ->
+ [true] type
+ *[false] const
+ } {$parent_exists ->
+ [true] parameter `{$param_name}` declared on the {$parent_prefix} `{$parent_name}`
+ *[false] parameter {$param_name}
+ }
+
+infer_source_kind_subdiag_generic_suggestion =
+ consider specifying the generic {$arg_count ->
+ [one] argument
+ *[other] arguments
+ }
+
+infer_source_kind_subdiag_let = {$kind ->
+ [with_pattern] consider giving `{$name}` an explicit type
+ [closure] consider giving this closure parameter an explicit type
+ *[other] consider giving this pattern a type
+}{$x_kind ->
+ [has_name] , where the {$prefix_kind ->
+ *[type] type for {$prefix}
+ [const_with_param] value of const parameter
+ [const] value of the constant
+ } `{$arg_name}` is specified
+ [underscore] , where the placeholders `_` are specified
+ *[empty] {""}
+}
+
+infer_srs_add = consider returning the local binding `{$ident}`
+infer_srs_add_one = consider returning one of these bindings
+
+infer_srs_remove = consider removing this semicolon
+infer_srs_remove_and_box = consider removing this semicolon and boxing the expressions
infer_stp_wrap_many = try wrapping the pattern in a variant of `{$path}`
-infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
+infer_stp_wrap_one = try wrapping the pattern in `{$variant}`
+infer_subtype = ...so that the {$requirement ->
+ [method_compat] method type is compatible with trait
+ [type_compat] associated type is compatible with trait
+ [const_compat] const is compatible with trait
+ [expr_assignable] expression is assignable
+ [if_else_different] `if` and `else` have incompatible types
+ [no_else] `if` missing an `else` returns `()`
+ [fn_main_correct_type] `main` function has the correct type
+ [fn_start_correct_type] `#[start]` function has the correct type
+ [intrinsic_correct_type] intrinsic has the correct type
+ [method_correct_type] method receiver has the correct type
+ *[other] types are compatible
+}
+infer_subtype_2 = ...so that {$requirement ->
+ [method_compat] method type is compatible with trait
+ [type_compat] associated type is compatible with trait
+ [const_compat] const is compatible with trait
+ [expr_assignable] expression is assignable
+ [if_else_different] `if` and `else` have incompatible types
+ [no_else] `if` missing an `else` returns `()`
+ [fn_main_correct_type] `main` function has the correct type
+ [fn_start_correct_type] `#[start]` function has the correct type
+ [intrinsic_correct_type] intrinsic has the correct type
+ [method_correct_type] method receiver has the correct type
+ *[other] types are compatible
+}
-infer_oc_method_compat = method not compatible with trait
-infer_oc_type_compat = type not compatible with trait
-infer_oc_const_compat = const not compatible with trait
-infer_oc_try_compat = `?` operator has incompatible types
-infer_oc_match_compat = `match` arms have incompatible types
-infer_oc_if_else_different = `if` and `else` have incompatible types
-infer_oc_no_else = `if` may be missing an `else` clause
-infer_oc_no_diverge = `else` clause of `let...else` does not diverge
-infer_oc_fn_main_correct_type = `main` function has wrong type
-infer_oc_fn_start_correct_type = `#[start]` function has wrong type
-infer_oc_intristic_correct_type = intrinsic has wrong type
-infer_oc_method_correct_type = mismatched `self` parameter type
-infer_oc_closure_selfref = closure/generator type that references itself
-infer_oc_cant_coerce = cannot coerce intrinsics to function pointers
-infer_oc_generic = mismatched types
+infer_suggest_accessing_field = you might have meant to use field `{$name}` whose type is `{$ty}`
+
+infer_suggest_add_let_for_letchains = consider adding `let`
+
+infer_tid_consider_borrowing = consider borrowing this type parameter in the trait
+infer_tid_param_help = the lifetime requirements from the `impl` do not correspond to the requirements in the `trait`
+
+infer_tid_rel_help = verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output
+infer_trait_impl_diff = `impl` item signature doesn't match `trait` item signature
+ .found = found `{$found}`
+ .expected = expected `{$expected}`
+ .expected_found = expected signature `{$expected}`
+ {" "}found signature `{$found}`
+
+infer_trait_placeholder_mismatch = implementation of `{$trait_def_id}` is not general enough
+ .label_satisfy = doesn't satisfy where-clause
+ .label_where = due to a where-clause on `{$def_id}`...
+ .label_dup = implementation of `{$trait_def_id}` is not general enough
-infer_meant_byte_literal = if you meant to write a byte literal, prefix with `b`
-infer_meant_char_literal = if you meant to write a `char` literal, use single quotes
-infer_meant_str_literal = if you meant to write a `str` literal, use double quotes
-infer_consider_specifying_length = consider specifying the actual array length
infer_try_cannot_convert = `?` operator cannot convert from `{$found}` to `{$expected}`
+
+infer_tuple_trailing_comma = use a trailing comma to create a tuple with one element
+
+infer_type_annotations_needed = {$source_kind ->
+ [closure] type annotations needed for the closure `{$source_name}`
+ [normal] type annotations needed for `{$source_name}`
+ *[other] type annotations needed
+}
+ .label = type must be known at this point
+
+infer_types_declared_different = these two types are declared with different lifetimes...
+infer_where_copy_predicates = copy the `where` clause predicates from the trait
+
+infer_where_remove = remove the `where` clause
diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs
index 65b3dd1a8..b1e819e83 100644
--- a/compiler/rustc_infer/src/errors/mod.rs
+++ b/compiler/rustc_infer/src/errors/mod.rs
@@ -71,7 +71,7 @@ pub struct AmbiguousImpl<'a> {
// Copy of `AnnotationRequired` for E0284
#[derive(Diagnostic)]
#[diag(infer_type_annotations_needed, code = "E0284")]
-pub struct AmbigousReturn<'a> {
+pub struct AmbiguousReturn<'a> {
#[primary_span]
pub span: Span,
pub source_kind: &'static str,
@@ -1085,7 +1085,7 @@ pub enum PlaceholderRelationLfNotSatisfied {
span: Span,
#[note(infer_prlf_defined_with_sub)]
sub_span: Span,
- #[note(infer_prlf_must_oultive_with_sup)]
+ #[note(infer_prlf_must_outlive_with_sup)]
sup_span: Span,
sub_symbol: Symbol,
sup_symbol: Symbol,
@@ -1098,7 +1098,7 @@ pub enum PlaceholderRelationLfNotSatisfied {
span: Span,
#[note(infer_prlf_defined_with_sub)]
sub_span: Span,
- #[note(infer_prlf_must_oultive_without_sup)]
+ #[note(infer_prlf_must_outlive_without_sup)]
sup_span: Span,
sub_symbol: Symbol,
#[note(infer_prlf_known_limitation)]
@@ -1110,7 +1110,7 @@ pub enum PlaceholderRelationLfNotSatisfied {
span: Span,
#[note(infer_prlf_defined_without_sub)]
sub_span: Span,
- #[note(infer_prlf_must_oultive_with_sup)]
+ #[note(infer_prlf_must_outlive_with_sup)]
sup_span: Span,
sup_symbol: Symbol,
#[note(infer_prlf_known_limitation)]
@@ -1122,7 +1122,7 @@ pub enum PlaceholderRelationLfNotSatisfied {
span: Span,
#[note(infer_prlf_defined_without_sub)]
sub_span: Span,
- #[note(infer_prlf_must_oultive_without_sup)]
+ #[note(infer_prlf_must_outlive_without_sup)]
sup_span: Span,
#[note(infer_prlf_known_limitation)]
note: (),
@@ -1488,8 +1488,8 @@ pub enum ObligationCauseFailureCode {
#[subdiagnostic]
subdiags: Vec<TypeErrorAdditionalDiags>,
},
- #[diag(infer_oc_intristic_correct_type, code = "E0308")]
- IntristicCorrectType {
+ #[diag(infer_oc_intrinsic_correct_type, code = "E0308")]
+ IntrinsicCorrectType {
#[primary_span]
span: Span,
#[subdiagnostic]
diff --git a/compiler/rustc_infer/src/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs
index d240d8e49..0c8854e96 100644
--- a/compiler/rustc_infer/src/infer/at.rs
+++ b/compiler/rustc_infer/src/infer/at.rs
@@ -30,8 +30,6 @@ use super::*;
use rustc_middle::ty::relate::{Relate, TypeRelation};
use rustc_middle::ty::{Const, ImplSubject};
-use std::cell::Cell;
-
/// Whether we should define opaque types or just treat them opaquely.
///
/// Currently only used to prevent predicate matching from matching anything
@@ -84,7 +82,6 @@ impl<'tcx> InferCtxt<'tcx> {
in_snapshot: self.in_snapshot.clone(),
universe: self.universe.clone(),
intercrate: self.intercrate,
- inside_canonicalization_ctxt: Cell::new(self.inside_canonicalization_ctxt()),
}
}
}
diff --git a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
index e808911a3..427d05c8b 100644
--- a/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
+++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs
@@ -16,7 +16,7 @@ use rustc_middle::ty::{self, BoundVar, InferConst, List, Ty, TyCtxt, TypeFlags,
use std::sync::atomic::Ordering;
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use smallvec::SmallVec;
impl<'tcx> InferCtxt<'tcx> {
@@ -205,7 +205,7 @@ impl CanonicalizeMode for CanonicalizeQueryResponse {
// `delay_span_bug` to allow type error over an ICE.
canonicalizer.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
- &format!("unexpected region in query response: `{:?}`", r),
+ format!("unexpected region in query response: `{:?}`", r),
);
r
}
@@ -561,15 +561,13 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
where
V: TypeFoldable<TyCtxt<'tcx>>,
{
- let _inside_canonical_ctxt_guard = infcx.set_canonicalization_ctxt();
-
let needs_canonical_flags = if canonicalize_region_mode.any() {
- TypeFlags::NEEDS_INFER |
+ TypeFlags::HAS_INFER |
TypeFlags::HAS_FREE_REGIONS | // `HAS_RE_PLACEHOLDER` implies `HAS_FREE_REGIONS`
TypeFlags::HAS_TY_PLACEHOLDER |
TypeFlags::HAS_CT_PLACEHOLDER
} else {
- TypeFlags::NEEDS_INFER
+ TypeFlags::HAS_INFER
| TypeFlags::HAS_RE_PLACEHOLDER
| TypeFlags::HAS_TY_PLACEHOLDER
| TypeFlags::HAS_CT_PLACEHOLDER
@@ -600,7 +598,7 @@ impl<'cx, 'tcx> Canonicalizer<'cx, 'tcx> {
// Once we have canonicalized `out_value`, it should not
// contain anything that ties it to this inference context
// anymore.
- debug_assert!(!out_value.needs_infer() && !out_value.has_placeholders());
+ debug_assert!(!out_value.has_infer() && !out_value.has_placeholders());
let canonical_variables =
tcx.mk_canonical_var_infos(&canonicalizer.universe_canonicalized_variables());
diff --git a/compiler/rustc_infer/src/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs
index fbb2257bf..2abdd5b0a 100644
--- a/compiler/rustc_infer/src/infer/canonical/mod.rs
+++ b/compiler/rustc_infer/src/infer/canonical/mod.rs
@@ -23,7 +23,7 @@
use crate::infer::{ConstVariableOrigin, ConstVariableOriginKind};
use crate::infer::{InferCtxt, RegionVariableOrigin, TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::subst::GenericArg;
use rustc_middle::ty::{self, List, TyCtxt};
diff --git a/compiler/rustc_infer/src/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs
index e98f68ae5..88256c819 100644
--- a/compiler/rustc_infer/src/infer/canonical/query_response.rs
+++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs
@@ -15,12 +15,12 @@ use crate::infer::canonical::{
use crate::infer::nll_relate::{TypeRelating, TypeRelatingDelegate};
use crate::infer::region_constraints::{Constraint, RegionConstraintData};
use crate::infer::{DefineOpaqueTypes, InferCtxt, InferOk, InferResult, NllRegionVariableOrigin};
-use crate::traits::query::{Fallible, NoSolution};
+use crate::traits::query::NoSolution;
use crate::traits::{Obligation, ObligationCause, PredicateObligation};
use crate::traits::{PredicateObligations, TraitEngine, TraitEngineExt};
use rustc_data_structures::captures::Captures;
-use rustc_index::vec::Idx;
-use rustc_index::vec::IndexVec;
+use rustc_index::Idx;
+use rustc_index::IndexVec;
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::mir::ConstraintCategory;
use rustc_middle::ty::fold::TypeFoldable;
@@ -57,7 +57,7 @@ impl<'tcx> InferCtxt<'tcx> {
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
fulfill_cx: &mut dyn TraitEngine<'tcx>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
+ ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
@@ -153,20 +153,22 @@ impl<'tcx> InferCtxt<'tcx> {
/// Used by the new solver as that one takes the opaque types at the end of a probe
/// to deal with multiple candidates without having to recompute them.
- pub fn clone_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+ pub fn clone_opaque_types_for_query_response(
+ &self,
+ ) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
self.inner
.borrow()
.opaque_type_storage
.opaque_types
.iter()
- .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
+ .map(|(k, v)| (*k, v.hidden_type.ty))
.collect()
}
- fn take_opaque_types_for_query_response(&self) -> Vec<(Ty<'tcx>, Ty<'tcx>)> {
+ fn take_opaque_types_for_query_response(&self) -> Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)> {
std::mem::take(&mut self.inner.borrow_mut().opaque_type_storage.opaque_types)
.into_iter()
- .map(|(k, v)| (self.tcx.mk_opaque(k.def_id.to_def_id(), k.substs), v.hidden_type.ty))
+ .map(|(k, v)| (k, v.hidden_type.ty))
.collect()
}
@@ -467,11 +469,11 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
GenericArgKind::Const(result_value) => {
- if let ty::ConstKind::Bound(debrujin, b) = result_value.kind() {
+ if let ty::ConstKind::Bound(debruijn, b) = result_value.kind() {
// ...in which case we would set `canonical_vars[0]` to `Some(const X)`.
// We only allow a `ty::INNERMOST` index in substitutions.
- assert_eq!(debrujin, ty::INNERMOST);
+ assert_eq!(debruijn, ty::INNERMOST);
opt_values[b] = Some(*original_value);
}
}
@@ -507,8 +509,22 @@ impl<'tcx> InferCtxt<'tcx> {
let a = substitute_value(self.tcx, &result_subst, a);
let b = substitute_value(self.tcx, &result_subst, b);
debug!(?a, ?b, "constrain opaque type");
- obligations
- .extend(self.at(cause, param_env).eq(DefineOpaqueTypes::Yes, a, b)?.obligations);
+ // We use equate here instead of, for example, just registering the
+ // opaque type's hidden value directly, because we may be instantiating
+ // a query response that was canonicalized in an InferCtxt that had
+ // a different defining anchor. In that case, we may have inferred
+ // `NonLocalOpaque := LocalOpaque` but can only instantiate it in
+ // the other direction as `LocalOpaque := NonLocalOpaque`. Using eq
+ // here allows us to try both directions (in `InferCtxt::handle_opaque_type`).
+ obligations.extend(
+ self.at(cause, param_env)
+ .eq(
+ DefineOpaqueTypes::Yes,
+ self.tcx.mk_opaque(a.def_id.to_def_id(), a.substs),
+ b,
+ )?
+ .obligations,
+ );
}
Ok(InferOk { value: result_subst, obligations })
diff --git a/compiler/rustc_infer/src/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs
index fe45b5ebe..b6b935de6 100644
--- a/compiler/rustc_infer/src/infer/combine.rs
+++ b/compiler/rustc_infer/src/infer/combine.rs
@@ -26,24 +26,17 @@ use super::equate::Equate;
use super::glb::Glb;
use super::lub::Lub;
use super::sub::Sub;
-use super::type_variable::TypeVariableValue;
-use super::{DefineOpaqueTypes, InferCtxt, MiscVariable, TypeTrace};
+use super::{DefineOpaqueTypes, InferCtxt, TypeTrace};
+use crate::infer::generalize::{self, CombineDelegate, Generalization};
use crate::traits::{Obligation, PredicateObligations};
-use rustc_data_structures::sso::SsoHashMap;
-use rustc_hir::def_id::DefId;
use rustc_middle::infer::canonical::OriginalQueryValues;
use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{
- self, AliasKind, FallibleTypeFolder, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable,
- TypeSuperFoldable, TypeVisitableExt,
-};
+use rustc_middle::ty::relate::{RelateResult, TypeRelation};
+use rustc_middle::ty::{self, AliasKind, InferConst, ToPredicate, Ty, TyCtxt, TypeVisitableExt};
use rustc_middle::ty::{IntType, UintType};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::DUMMY_SP;
#[derive(Clone)]
pub struct CombineFields<'infcx, 'tcx> {
@@ -55,13 +48,6 @@ pub struct CombineFields<'infcx, 'tcx> {
pub define_opaque_types: DefineOpaqueTypes,
}
-#[derive(Copy, Clone, Debug)]
-pub enum RelationDir {
- SubtypeOf,
- SupertypeOf,
- EqTo,
-}
-
impl<'tcx> InferCtxt<'tcx> {
pub fn super_combine_tys<R>(
&self,
@@ -73,6 +59,8 @@ impl<'tcx> InferCtxt<'tcx> {
R: ObligationEmittingRelation<'tcx>,
{
let a_is_expected = relation.a_is_expected();
+ debug_assert!(!a.has_escaping_bound_vars());
+ debug_assert!(!b.has_escaping_bound_vars());
match (a.kind(), b.kind()) {
// Relate integral variables to other types
@@ -125,9 +113,7 @@ impl<'tcx> InferCtxt<'tcx> {
bug!()
}
- (_, ty::Alias(AliasKind::Projection, _)) | (ty::Alias(AliasKind::Projection, _), _)
- if self.tcx.trait_solver_next() =>
- {
+ (_, ty::Alias(..)) | (ty::Alias(..), _) if self.tcx.trait_solver_next() => {
relation.register_type_relate_obligation(a, b);
Ok(a)
}
@@ -149,7 +135,7 @@ impl<'tcx> InferCtxt<'tcx> {
Ok(a)
}
- _ => ty::relate::super_relate_tys(relation, a, b),
+ _ => ty::relate::structurally_relate_tys(relation, a, b),
}
}
@@ -163,6 +149,8 @@ impl<'tcx> InferCtxt<'tcx> {
R: ObligationEmittingRelation<'tcx>,
{
debug!("{}.consts({:?}, {:?})", relation.tag(), a, b);
+ debug_assert!(!a.has_escaping_bound_vars());
+ debug_assert!(!b.has_escaping_bound_vars());
if a == b {
return Ok(a);
}
@@ -192,7 +180,7 @@ impl<'tcx> InferCtxt<'tcx> {
self.tcx.check_tys_might_be_eq(canonical).map_err(|_| {
self.tcx.sess.delay_span_bug(
DUMMY_SP,
- &format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
+ format!("cannot relate consts of different types (a={:?}, b={:?})", a, b,),
)
})
});
@@ -204,13 +192,13 @@ impl<'tcx> InferCtxt<'tcx> {
// HACK: equating both sides with `[const error]` eagerly prevents us
// from leaving unconstrained inference vars during things like impl
// matching in the solver.
- let a_error = self.tcx.const_error_with_guaranteed(a.ty(), guar);
+ let a_error = self.tcx.const_error(a.ty(), guar);
if let ty::ConstKind::Infer(InferConst::Var(vid)) = a.kind() {
- return self.unify_const_variable(vid, a_error);
+ return self.unify_const_variable(vid, a_error, relation.param_env());
}
- let b_error = self.tcx.const_error_with_guaranteed(b.ty(), guar);
+ let b_error = self.tcx.const_error(b.ty(), guar);
if let ty::ConstKind::Infer(InferConst::Var(vid)) = b.kind() {
- return self.unify_const_variable(vid, b_error);
+ return self.unify_const_variable(vid, b_error, relation.param_env());
}
return Ok(if relation.a_is_expected() { a_error } else { b_error });
@@ -232,32 +220,22 @@ impl<'tcx> InferCtxt<'tcx> {
}
(ty::ConstKind::Infer(InferConst::Var(vid)), _) => {
- return self.unify_const_variable(vid, b);
+ return self.unify_const_variable(vid, b, relation.param_env());
}
(_, ty::ConstKind::Infer(InferConst::Var(vid))) => {
- return self.unify_const_variable(vid, a);
+ return self.unify_const_variable(vid, a, relation.param_env());
}
- (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => {
- // FIXME(#59490): Need to remove the leak check to accommodate
- // escaping bound variables here.
- if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
- relation.register_const_equate_obligation(a, b);
- }
+ (ty::ConstKind::Unevaluated(..), _) | (_, ty::ConstKind::Unevaluated(..))
+ if self.tcx.lazy_normalization() =>
+ {
+ relation.register_const_equate_obligation(a, b);
return Ok(b);
}
- (_, ty::ConstKind::Unevaluated(..)) if self.tcx.lazy_normalization() => {
- // FIXME(#59490): Need to remove the leak check to accommodate
- // escaping bound variables here.
- if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
- relation.register_const_equate_obligation(a, b);
- }
- return Ok(a);
- }
_ => {}
}
- ty::relate::super_relate_consts(relation, a, b)
+ ty::relate::structurally_relate_consts(relation, a, b)
}
/// Unifies the const variable `target_vid` with the given constant.
@@ -299,24 +277,17 @@ impl<'tcx> InferCtxt<'tcx> {
&self,
target_vid: ty::ConstVid<'tcx>,
ct: ty::Const<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
- let (for_universe, span) = {
- let mut inner = self.inner.borrow_mut();
- let variable_table = &mut inner.const_unification_table();
- let var_value = variable_table.probe_value(target_vid);
- match var_value.val {
- ConstVariableValue::Known { value } => {
- bug!("instantiating {:?} which has a known value {:?}", target_vid, value)
- }
- ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span),
- }
- };
- let value = ct.try_fold_with(&mut ConstInferUnifier {
- infcx: self,
- span,
- for_universe,
+ let span =
+ self.inner.borrow_mut().const_unification_table().probe_value(target_vid).origin.span;
+ let Generalization { value, needs_wf: _ } = generalize::generalize(
+ self,
+ &mut CombineDelegate { infcx: self, span, param_env },
+ ct,
target_vid,
- })?;
+ ty::Variance::Invariant,
+ )?;
self.inner.borrow_mut().const_unification_table().union_value(
target_vid,
@@ -397,12 +368,10 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
pub fn instantiate(
&mut self,
a_ty: Ty<'tcx>,
- dir: RelationDir,
+ ambient_variance: ty::Variance,
b_vid: ty::TyVid,
a_is_expected: bool,
) -> RelateResult<'tcx, ()> {
- use self::RelationDir::*;
-
// Get the actual variable that b_vid has been inferred to
debug_assert!(self.infcx.inner.borrow_mut().type_variables().probe(b_vid).is_unknown());
@@ -417,7 +386,18 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// `'?2` and `?3` are fresh region/type inference
// variables. (Down below, we will relate `a_ty <: b_ty`,
// adding constraints like `'x: '?2` and `?1 <: ?3`.)
- let Generalization { ty: b_ty, needs_wf } = self.generalize(a_ty, b_vid, dir)?;
+ let Generalization { value: b_ty, needs_wf } = generalize::generalize(
+ self.infcx,
+ &mut CombineDelegate {
+ infcx: self.infcx,
+ param_env: self.param_env,
+ span: self.trace.span(),
+ },
+ a_ty,
+ b_vid,
+ ambient_variance,
+ )?;
+
debug!(?b_ty);
self.infcx.inner.borrow_mut().type_variables().instantiate(b_vid, b_ty);
@@ -436,78 +416,23 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
// relations wind up attributed to the same spans. We need
// to associate causes/spans with each of the relations in
// the stack to get this right.
- match dir {
- EqTo => self.equate(a_is_expected).relate(a_ty, b_ty),
- SubtypeOf => self.sub(a_is_expected).relate(a_ty, b_ty),
- SupertypeOf => self.sub(a_is_expected).relate_with_variance(
+ match ambient_variance {
+ ty::Variance::Invariant => self.equate(a_is_expected).relate(a_ty, b_ty),
+ ty::Variance::Covariant => self.sub(a_is_expected).relate(a_ty, b_ty),
+ ty::Variance::Contravariant => self.sub(a_is_expected).relate_with_variance(
ty::Contravariant,
ty::VarianceDiagInfo::default(),
a_ty,
b_ty,
),
+ ty::Variance::Bivariant => {
+ unreachable!("no code should be generalizing bivariantly (currently)")
+ }
}?;
Ok(())
}
- /// Attempts to generalize `ty` for the type variable `for_vid`.
- /// This checks for cycle -- that is, whether the type `ty`
- /// references `for_vid`. The `dir` is the "direction" for which we
- /// a performing the generalization (i.e., are we producing a type
- /// that can be used as a supertype etc).
- ///
- /// Preconditions:
- ///
- /// - `for_vid` is a "root vid"
- #[instrument(skip(self), level = "trace", ret)]
- fn generalize(
- &self,
- ty: Ty<'tcx>,
- for_vid: ty::TyVid,
- dir: RelationDir,
- ) -> RelateResult<'tcx, Generalization<'tcx>> {
- // Determine the ambient variance within which `ty` appears.
- // The surrounding equation is:
- //
- // ty [op] ty2
- //
- // where `op` is either `==`, `<:`, or `:>`. This maps quite
- // naturally.
- let ambient_variance = match dir {
- RelationDir::EqTo => ty::Invariant,
- RelationDir::SubtypeOf => ty::Covariant,
- RelationDir::SupertypeOf => ty::Contravariant,
- };
-
- trace!(?ambient_variance);
-
- let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) {
- v @ TypeVariableValue::Known { .. } => {
- bug!("instantiating {:?} which has a known value {:?}", for_vid, v,)
- }
- TypeVariableValue::Unknown { universe } => universe,
- };
-
- trace!(?for_universe);
- trace!(?self.trace);
-
- let mut generalize = Generalizer {
- infcx: self.infcx,
- cause: &self.trace.cause,
- for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
- for_universe,
- ambient_variance,
- needs_wf: false,
- root_ty: ty,
- param_env: self.param_env,
- cache: SsoHashMap::new(),
- };
-
- let ty = generalize.relate(ty, ty)?;
- let needs_wf = generalize.needs_wf;
- Ok(Generalization { ty, needs_wf })
- }
-
pub fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>) {
self.obligations.extend(obligations.into_iter());
}
@@ -519,320 +444,13 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> {
}
}
-struct Generalizer<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'tcx>,
-
- /// The span, used when creating new type variables and things.
- cause: &'cx ObligationCause<'tcx>,
-
- /// The vid of the type variable that is in the process of being
- /// instantiated; if we find this within the type we are folding,
- /// that means we would have created a cyclic type.
- for_vid_sub_root: ty::TyVid,
-
- /// The universe of the type variable that is in the process of
- /// being instantiated. Any fresh variables that we create in this
- /// process should be in that same universe.
- for_universe: ty::UniverseIndex,
-
- /// Track the variance as we descend into the type.
- ambient_variance: ty::Variance,
-
- /// See the field `needs_wf` in `Generalization`.
- needs_wf: bool,
-
- /// The root type that we are generalizing. Used when reporting cycles.
- root_ty: Ty<'tcx>,
-
- param_env: ty::ParamEnv<'tcx>,
-
- cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
-}
-
-/// Result from a generalization operation. This includes
-/// not only the generalized type, but also a bool flag
-/// indicating whether further WF checks are needed.
-#[derive(Debug)]
-struct Generalization<'tcx> {
- ty: Ty<'tcx>,
-
- /// If true, then the generalized type may not be well-formed,
- /// even if the source type is well-formed, so we should add an
- /// additional check to enforce that it is. This arises in
- /// particular around 'bivariant' type parameters that are only
- /// constrained by a where-clause. As an example, imagine a type:
- ///
- /// struct Foo<A, B> where A: Iterator<Item = B> {
- /// data: A
- /// }
- ///
- /// here, `A` will be covariant, but `B` is
- /// unconstrained. However, whatever it is, for `Foo` to be WF, it
- /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
- /// then after generalization we will wind up with a type like
- /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
- /// ?D>` (or `>:`), we will wind up with the requirement that `?A
- /// <: ?C`, but no particular relationship between `?B` and `?D`
- /// (after all, we do not know the variance of the normalized form
- /// of `A::Item` with respect to `A`). If we do nothing else, this
- /// may mean that `?D` goes unconstrained (as in #41677). So, in
- /// this scenario where we create a new type variable in a
- /// bivariant context, we set the `needs_wf` flag to true. This
- /// will force the calling code to check that `WF(Foo<?C, ?D>)`
- /// holds, which in turn implies that `?C::Item == ?D`. So once
- /// `?C` is constrained, that should suffice to restrict `?D`.
- needs_wf: bool,
-}
-
-impl<'tcx> TypeRelation<'tcx> for Generalizer<'_, 'tcx> {
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
-
- fn tag(&self) -> &'static str {
- "Generalizer"
- }
-
- fn a_is_expected(&self) -> bool {
- true
- }
-
- fn binders<T>(
- &mut self,
- a: ty::Binder<'tcx, T>,
- b: ty::Binder<'tcx, T>,
- ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
- where
- T: Relate<'tcx>,
- {
- Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
- }
-
- fn relate_item_substs(
- &mut self,
- item_def_id: DefId,
- a_subst: SubstsRef<'tcx>,
- b_subst: SubstsRef<'tcx>,
- ) -> RelateResult<'tcx, SubstsRef<'tcx>> {
- if self.ambient_variance == ty::Variance::Invariant {
- // Avoid fetching the variance if we are in an invariant
- // context; no need, and it can induce dependency cycles
- // (e.g., #41849).
- relate::relate_substs(self, a_subst, b_subst)
- } else {
- let tcx = self.tcx();
- let opt_variances = tcx.variances_of(item_def_id);
- relate::relate_substs_with_variances(
- self,
- item_def_id,
- &opt_variances,
- a_subst,
- b_subst,
- true,
- )
- }
- }
-
- fn relate_with_variance<T: Relate<'tcx>>(
- &mut self,
- variance: ty::Variance,
- _info: ty::VarianceDiagInfo<'tcx>,
- a: T,
- b: T,
- ) -> RelateResult<'tcx, T> {
- let old_ambient_variance = self.ambient_variance;
- self.ambient_variance = self.ambient_variance.xform(variance);
-
- let result = self.relate(a, b);
- self.ambient_variance = old_ambient_variance;
- result
- }
-
- fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- assert_eq!(t, t2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
-
- if let Some(&result) = self.cache.get(&t) {
- return Ok(result);
- }
- debug!("generalize: t={:?}", t);
-
- // Check to see whether the type we are generalizing references
- // any other type variable related to `vid` via
- // subtyping. This is basically our "occurs check", preventing
- // us from creating infinitely sized types.
- let result = match *t.kind() {
- ty::Infer(ty::TyVar(vid)) => {
- let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
- let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid);
- if sub_vid == self.for_vid_sub_root {
- // If sub-roots are equal, then `for_vid` and
- // `vid` are related via subtyping.
- Err(TypeError::CyclicTy(self.root_ty))
- } else {
- let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
- match probe {
- TypeVariableValue::Known { value: u } => {
- debug!("generalize: known value {:?}", u);
- self.relate(u, u)
- }
- TypeVariableValue::Unknown { universe } => {
- match self.ambient_variance {
- // Invariant: no need to make a fresh type variable.
- ty::Invariant => {
- if self.for_universe.can_name(universe) {
- return Ok(t);
- }
- }
-
- // Bivariant: make a fresh var, but we
- // may need a WF predicate. See
- // comment on `needs_wf` field for
- // more info.
- ty::Bivariant => self.needs_wf = true,
-
- // Co/contravariant: this will be
- // sufficiently constrained later on.
- ty::Covariant | ty::Contravariant => (),
- }
-
- let origin =
- *self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
- let new_var_id = self
- .infcx
- .inner
- .borrow_mut()
- .type_variables()
- .new_var(self.for_universe, origin);
- let u = self.tcx().mk_ty_var(new_var_id);
-
- // Record that we replaced `vid` with `new_var_id` as part of a generalization
- // operation. This is needed to detect cyclic types. To see why, see the
- // docs in the `type_variables` module.
- self.infcx.inner.borrow_mut().type_variables().sub(vid, new_var_id);
- debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
- Ok(u)
- }
- }
- }
- }
- ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
- // No matter what mode we are in,
- // integer/floating-point types must be equal to be
- // relatable.
- Ok(t)
- }
- ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
- let s = self.relate(substs, substs)?;
- Ok(if s == substs { t } else { self.infcx.tcx.mk_opaque(def_id, s) })
- }
- _ => relate::super_relate_tys(self, t, t),
- }?;
-
- self.cache.insert(t, result);
- Ok(result)
- }
-
- fn regions(
- &mut self,
- r: ty::Region<'tcx>,
- r2: ty::Region<'tcx>,
- ) -> RelateResult<'tcx, ty::Region<'tcx>> {
- assert_eq!(r, r2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
-
- debug!("generalize: regions r={:?}", r);
-
- match *r {
- // Never make variables for regions bound within the type itself,
- // nor for erased regions.
- ty::ReLateBound(..) | ty::ReErased => {
- return Ok(r);
- }
-
- ty::ReError(_) => {
- return Ok(r);
- }
-
- ty::RePlaceholder(..)
- | ty::ReVar(..)
- | ty::ReStatic
- | ty::ReEarlyBound(..)
- | ty::ReFree(..) => {
- // see common code below
- }
- }
-
- // If we are in an invariant context, we can re-use the region
- // as is, unless it happens to be in some universe that we
- // can't name. (In the case of a region *variable*, we could
- // use it if we promoted it into our universe, but we don't
- // bother.)
- if let ty::Invariant = self.ambient_variance {
- let r_universe = self.infcx.universe_of_region(r);
- if self.for_universe.can_name(r_universe) {
- return Ok(r);
- }
- }
-
- // FIXME: This is non-ideal because we don't give a
- // very descriptive origin for this region variable.
- Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.cause.span), self.for_universe))
- }
-
- fn consts(
- &mut self,
- c: ty::Const<'tcx>,
- c2: ty::Const<'tcx>,
- ) -> RelateResult<'tcx, ty::Const<'tcx>> {
- assert_eq!(c, c2); // we are abusing TypeRelation here; both LHS and RHS ought to be ==
-
- match c.kind() {
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let variable_table = &mut inner.const_unification_table();
- let var_value = variable_table.probe_value(vid);
- match var_value.val {
- ConstVariableValue::Known { value: u } => {
- drop(inner);
- self.relate(u, u)
- }
- ConstVariableValue::Unknown { universe } => {
- if self.for_universe.can_name(universe) {
- Ok(c)
- } else {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.for_universe },
- });
- Ok(self.tcx().mk_const(new_var_id, c.ty()))
- }
- }
- }
- }
- ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
- let substs = self.relate_with_variance(
- ty::Variance::Invariant,
- ty::VarianceDiagInfo::default(),
- substs,
- substs,
- )?;
- Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
- }
- _ => relate::super_relate_consts(self, c, c),
- }
- }
-}
-
pub trait ObligationEmittingRelation<'tcx>: TypeRelation<'tcx> {
/// Register obligations that must hold in order for this relation to hold
fn register_obligations(&mut self, obligations: PredicateObligations<'tcx>);
/// Register predicates that must hold in order for this relation to hold. Uses
/// a default obligation cause, [`ObligationEmittingRelation::register_obligations`] should
- /// be used if control over the obligaton causes is required.
+ /// be used if control over the obligation causes is required.
fn register_predicates(&mut self, obligations: impl IntoIterator<Item: ToPredicate<'tcx>>);
/// Register an obligation that both constants must be equal to each other.
@@ -878,135 +496,3 @@ fn float_unification_error<'tcx>(
let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v;
TypeError::FloatMismatch(ExpectedFound::new(a_is_expected, a, b))
}
-
-struct ConstInferUnifier<'cx, 'tcx> {
- infcx: &'cx InferCtxt<'tcx>,
-
- span: Span,
-
- for_universe: ty::UniverseIndex,
-
- /// The vid of the const variable that is in the process of being
- /// instantiated; if we find this within the const we are folding,
- /// that means we would have created a cyclic const.
- target_vid: ty::ConstVid<'tcx>,
-}
-
-impl<'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for ConstInferUnifier<'_, 'tcx> {
- type Error = TypeError<'tcx>;
-
- fn interner(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- #[instrument(level = "debug", skip(self), ret)]
- fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, TypeError<'tcx>> {
- match t.kind() {
- &ty::Infer(ty::TyVar(vid)) => {
- let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid);
- let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid);
- match probe {
- TypeVariableValue::Known { value: u } => {
- debug!("ConstOccursChecker: known value {:?}", u);
- u.try_fold_with(self)
- }
- TypeVariableValue::Unknown { universe } => {
- if self.for_universe.can_name(universe) {
- return Ok(t);
- }
-
- let origin =
- *self.infcx.inner.borrow_mut().type_variables().var_origin(vid);
- let new_var_id = self
- .infcx
- .inner
- .borrow_mut()
- .type_variables()
- .new_var(self.for_universe, origin);
- Ok(self.interner().mk_ty_var(new_var_id))
- }
- }
- }
- ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => Ok(t),
- _ => t.try_super_fold_with(self),
- }
- }
-
- #[instrument(level = "debug", skip(self), ret)]
- fn try_fold_region(
- &mut self,
- r: ty::Region<'tcx>,
- ) -> Result<ty::Region<'tcx>, TypeError<'tcx>> {
- debug!("ConstInferUnifier: r={:?}", r);
-
- match *r {
- // Never make variables for regions bound within the type itself,
- // nor for erased regions.
- ty::ReLateBound(..) | ty::ReErased | ty::ReError(_) => {
- return Ok(r);
- }
-
- ty::RePlaceholder(..)
- | ty::ReVar(..)
- | ty::ReStatic
- | ty::ReEarlyBound(..)
- | ty::ReFree(..) => {
- // see common code below
- }
- }
-
- let r_universe = self.infcx.universe_of_region(r);
- if self.for_universe.can_name(r_universe) {
- return Ok(r);
- } else {
- // FIXME: This is non-ideal because we don't give a
- // very descriptive origin for this region variable.
- Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe))
- }
- }
-
- #[instrument(level = "debug", skip(self), ret)]
- fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, TypeError<'tcx>> {
- match c.kind() {
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
- // Check if the current unification would end up
- // unifying `target_vid` with a const which contains
- // an inference variable which is unioned with `target_vid`.
- //
- // Not doing so can easily result in stack overflows.
- if self
- .infcx
- .inner
- .borrow_mut()
- .const_unification_table()
- .unioned(self.target_vid, vid)
- {
- return Err(TypeError::CyclicConst(c));
- }
-
- let var_value =
- self.infcx.inner.borrow_mut().const_unification_table().probe_value(vid);
- match var_value.val {
- ConstVariableValue::Known { value: u } => u.try_fold_with(self),
- ConstVariableValue::Unknown { universe } => {
- if self.for_universe.can_name(universe) {
- Ok(c)
- } else {
- let new_var_id =
- self.infcx.inner.borrow_mut().const_unification_table().new_key(
- ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown {
- universe: self.for_universe,
- },
- },
- );
- Ok(self.interner().mk_const(new_var_id, c.ty()))
- }
- }
- }
- }
- _ => c.try_super_fold_with(self),
- }
- }
-}
diff --git a/compiler/rustc_infer/src/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs
index fe4a2dd38..42dfe4f6b 100644
--- a/compiler/rustc_infer/src/infer/equate.rs
+++ b/compiler/rustc_infer/src/infer/equate.rs
@@ -1,7 +1,7 @@
use crate::infer::DefineOpaqueTypes;
use crate::traits::PredicateObligations;
-use super::combine::{CombineFields, ObligationEmittingRelation, RelationDir};
+use super::combine::{CombineFields, ObligationEmittingRelation};
use super::Subtype;
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
@@ -88,11 +88,11 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
}
(&ty::Infer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, RelationDir::EqTo, a_id, self.a_is_expected)?;
+ self.fields.instantiate(b, ty::Invariant, a_id, self.a_is_expected)?;
}
(_, &ty::Infer(TyVar(b_id))) => {
- self.fields.instantiate(a, RelationDir::EqTo, b_id, self.a_is_expected)?;
+ self.fields.instantiate(a, ty::Invariant, b_id, self.a_is_expected)?;
}
(
@@ -104,7 +104,8 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
- && def_id.is_local() =>
+ && def_id.is_local()
+ && !self.tcx().trait_solver_next() =>
{
self.fields.obligations.extend(
infcx
@@ -178,7 +179,7 @@ impl<'tcx> TypeRelation<'tcx> for Equate<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
- // A binder is equal to itself if it's structually equal to itself
+ // A binder is equal to itself if it's structurally equal to itself
if a == b {
return Ok(a);
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
index 9e5f6d107..35c05e80b 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs
@@ -74,7 +74,6 @@ use rustc_middle::ty::{
self, error::TypeError, List, Region, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable,
TypeVisitable, TypeVisitableExt,
};
-use rustc_span::DUMMY_SP;
use rustc_span::{sym, symbol::kw, BytePos, DesugaringKind, Pos, Span};
use rustc_target::spec::abi;
use std::ops::{ControlFlow, Deref};
@@ -138,7 +137,7 @@ impl Drop for TypeErrCtxt<'_, '_> {
self.infcx
.tcx
.sess
- .delay_span_bug(DUMMY_SP, "used a `TypeErrCtxt` without failing compilation");
+ .delay_good_path_bug("used a `TypeErrCtxt` without raising an error or lint");
}
}
}
@@ -283,9 +282,9 @@ fn emit_msg_span(
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {
- err.span_note(span, &message);
+ err.span_note(span, message);
} else {
- err.note(&message);
+ err.note(message);
}
}
@@ -299,9 +298,9 @@ fn label_msg_span(
let message = format!("{}{}{}", prefix, description, suffix);
if let Some(span) = span {
- err.span_label(span, &message);
+ err.span_label(span, message);
} else {
- err.note(&message);
+ err.note(message);
}
}
@@ -403,7 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
let future_trait = self.tcx.require_lang_item(LangItem::Future, None);
let item_def_id = self.tcx.associated_item_def_ids(future_trait)[0];
- self.tcx.bound_explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
+ self.tcx.explicit_item_bounds(def_id).subst_iter_copied(self.tcx, substs).find_map(
|(predicate, _)| {
predicate
.kind()
@@ -1826,7 +1825,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
s
};
if !(values.expected.is_simple_text() && values.found.is_simple_text())
- || (exp_found.map_or(false, |ef| {
+ || (exp_found.is_some_and(|ef| {
// This happens when the type error is a subset of the expectation,
// like when you have two references but one is `usize` and the other
// is `f32`. In those cases we still want to show the `note`. If the
@@ -1878,7 +1877,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let exp_found = match terr {
// `terr` has more accurate type information than `exp_found` in match expressions.
ty::error::TypeError::Sorts(terr)
- if exp_found.map_or(false, |ef| terr.found == ef.found) =>
+ if exp_found.is_some_and(|ef| terr.found == ef.found) =>
{
Some(terr)
}
@@ -1927,6 +1926,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
{
let span = self.tcx.def_span(def_id);
diag.span_note(span, "this closure does not fulfill the lifetime requirements");
+ self.suggest_for_all_lifetime_closure(span, self.tcx.hir().get_by_def_id(def_id), &exp_found, diag);
}
// It reads better to have the error origin as the final
@@ -1961,7 +1961,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
if let Ok(code) = self.tcx.sess().source_map().span_to_snippet(span)
&& let Some(code) = code.strip_prefix('\'').and_then(|s| s.strip_suffix('\''))
&& !code.starts_with("\\u") // forbid all Unicode escapes
- && code.chars().next().map_or(false, |c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
+ && code.chars().next().is_some_and(|c| c.is_ascii()) // forbids literal Unicode characters beyond ASCII
{
suggestions.push(TypeErrorAdditionalDiags::MeantByteLiteral { span, code: escape_literal(code) })
}
@@ -2329,7 +2329,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
.source_map()
.span_to_prev_source(p.span.shrink_to_hi())
.ok()
- .map_or(false, |s| *s.as_bytes().last().unwrap() == b'&')
+ .is_some_and(|s| *s.as_bytes().last().unwrap() == b'&')
{
add_lt_suggs
.push(Some(
@@ -2354,7 +2354,9 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
let labeled_user_string = match bound_kind {
GenericKind::Param(ref p) => format!("the parameter type `{}`", p),
GenericKind::Alias(ref p) => match p.kind(self.tcx) {
- ty::AliasKind::Projection => format!("the associated type `{}`", p),
+ ty::AliasKind::Projection | ty::AliasKind::Inherent => {
+ format!("the associated type `{}`", p)
+ }
ty::AliasKind::Opaque => format!("the opaque type `{}`", p),
},
};
@@ -2395,7 +2397,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
} else {
let consider = format!("{} `{}: {}`...", msg, bound_kind, sub);
- err.help(&consider);
+ err.help(consider);
}
}
@@ -2625,7 +2627,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
);
err.span_note(
sup_trace.cause.span,
- &format!("...so that the {}", sup_trace.cause.as_requirement_str()),
+ format!("...so that the {}", sup_trace.cause.as_requirement_str()),
);
err.note_expected_found(&"", sup_expected, &"", sup_found);
@@ -2721,7 +2723,7 @@ impl<'tcx> TypeRelation<'tcx> for SameTypeModuloInfer<'_, 'tcx> {
| (ty::Infer(ty::InferTy::TyVar(_)), _)
| (_, ty::Infer(ty::InferTy::TyVar(_))) => Ok(a),
(ty::Infer(_), _) | (_, ty::Infer(_)) => Err(TypeError::Mismatch),
- _ => relate::super_relate_tys(self, a, b),
+ _ => relate::structurally_relate_tys(self, a, b),
}
}
@@ -2885,7 +2887,7 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> {
LetElse => ObligationCauseFailureCode::NoDiverge { span, subdiags },
MainFunctionType => ObligationCauseFailureCode::FnMainCorrectType { span },
StartFunctionType => ObligationCauseFailureCode::FnStartCorrectType { span, subdiags },
- IntrinsicType => ObligationCauseFailureCode::IntristicCorrectType { span, subdiags },
+ IntrinsicType => ObligationCauseFailureCode::IntrinsicCorrectType { span, subdiags },
MethodReceiver => ObligationCauseFailureCode::MethodCorrectType { span, subdiags },
// In the case where we have no more specific thing to
@@ -2942,7 +2944,7 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> {
IfExpressionWithNoElse => "no_else",
MainFunctionType => "fn_main_correct_type",
StartFunctionType => "fn_start_correct_type",
- IntrinsicType => "intristic_correct_type",
+ IntrinsicType => "intrinsic_correct_type",
MethodReceiver => "method_correct_type",
_ => "other",
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
index 75cc4e257..f3b2ec4c5 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- AmbigousReturn, AmbiguousImpl, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
+ AmbiguousImpl, AmbiguousReturn, AnnotationRequired, InferenceBadError, NeedTypeInfoInGenerator,
SourceKindMultiSuggestion, SourceKindSubdiag,
};
use crate::infer::error_reporting::TypeErrCtxt;
@@ -31,7 +31,7 @@ pub enum TypeAnnotationNeeded {
/// ```
E0282,
/// An implementation cannot be chosen unambiguously because of lack of information.
- /// ```compile_fail,E0283
+ /// ```compile_fail,E0790
/// let _ = Default::default();
/// ```
E0283,
@@ -368,7 +368,7 @@ impl<'tcx> InferCtxt<'tcx> {
bad_label,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ TypeAnnotationNeeded::E0284 => AmbiguousReturn {
span,
source_kind,
source_name,
@@ -573,7 +573,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
bad_label: None,
}
.into_diagnostic(&self.tcx.sess.parse_sess.span_diagnostic),
- TypeAnnotationNeeded::E0284 => AmbigousReturn {
+ TypeAnnotationNeeded::E0284 => AmbiguousReturn {
span,
source_kind,
source_name: &name,
@@ -671,7 +671,7 @@ impl<'tcx> InferSource<'tcx> {
receiver.span.from_expansion()
}
InferSourceKind::ClosureReturn { data, should_wrap_expr, .. } => {
- data.span().from_expansion() || should_wrap_expr.map_or(false, Span::from_expansion)
+ data.span().from_expansion() || should_wrap_expr.is_some_and(Span::from_expansion)
}
};
source_from_expansion || self.span.from_expansion()
@@ -984,7 +984,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> {
) -> impl Iterator<Item = InsertableGenericArgs<'tcx>> + 'a {
let tcx = self.infcx.tcx;
let have_turbofish = path.segments.iter().any(|segment| {
- segment.args.map_or(false, |args| args.args.iter().any(|arg| arg.is_ty_or_const()))
+ segment.args.is_some_and(|args| args.args.iter().any(|arg| arg.is_ty_or_const()))
});
// The last segment of a path often has `Res::Err` and the
// correct `Res` is the one of the whole path.
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
index da0271a34..1a60bab18 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs
@@ -21,7 +21,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
///
/// Consider a case where we have
///
- /// ```compile_fail,E0623
+ /// ```compile_fail
/// fn foo(x: &mut Vec<&u8>, y: &u8) {
/// x.push(y);
/// }
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
index fec04af23..0df417d09 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs
@@ -14,7 +14,7 @@ use rustc_middle::ty::{self, Region, TyCtxt};
/// br - the bound region corresponding to the above region which is of type `BrAnon(_)`
///
/// # Example
-/// ```compile_fail,E0623
+/// ```compile_fail
/// fn foo(x: &mut Vec<&u8>, y: &u8)
/// { x.push(y); }
/// ```
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
index c1ea0a0d9..c9c1f0aea 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs
@@ -261,11 +261,16 @@ impl<'tcx> NiceRegionError<'_, 'tcx> {
(false, None, None, Some(span), String::new())
};
- let expected_trait_ref = self
- .cx
- .resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, expected_substs));
- let actual_trait_ref =
- self.cx.resolve_vars_if_possible(self.cx.tcx.mk_trait_ref(trait_def_id, actual_substs));
+ let expected_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
+ self.cx.tcx,
+ trait_def_id,
+ expected_substs,
+ ));
+ let actual_trait_ref = self.cx.resolve_vars_if_possible(ty::TraitRef::new(
+ self.cx.tcx,
+ trait_def_id,
+ actual_substs,
+ ));
// Search the expected and actual trait references to see (a)
// whether the sub/sup placeholders appear in them (sometimes
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
index 22c1e3871..aad988582 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs
@@ -299,7 +299,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
span,
- &format!("{consider} `{ty}`'s {explicit_static}"),
+ format!("{consider} `{ty}`'s {explicit_static}"),
&lifetime_name,
Applicability::MaybeIncorrect,
);
@@ -312,13 +312,10 @@ pub fn suggest_new_region_bound(
Applicability::MaybeIncorrect,
);
}
- } else if opaque.bounds.iter().any(|arg| match arg {
- GenericBound::Outlives(Lifetime { ident, .. })
- if ident.name.to_string() == lifetime_name =>
- {
- true
- }
- _ => false,
+ } else if opaque.bounds.iter().any(|arg| {
+ matches!(arg,
+ GenericBound::Outlives(Lifetime { ident, .. })
+ if ident.name.to_string() == lifetime_name )
}) {
} else {
// get a lifetime name of existing named lifetimes if any
@@ -370,7 +367,7 @@ pub fn suggest_new_region_bound(
spans_suggs
.push((fn_return.span.shrink_to_hi(), format!(" + {name} ")));
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"{declare} `{ty}` {captures}, {use_lt}",
),
spans_suggs,
@@ -379,7 +376,7 @@ pub fn suggest_new_region_bound(
} else {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!("{declare} `{ty}` {captures}, {explicit}",),
+ format!("{declare} `{ty}` {captures}, {explicit}",),
&plus_lt,
Applicability::MaybeIncorrect,
);
@@ -390,7 +387,7 @@ pub fn suggest_new_region_bound(
if let LifetimeName::ImplicitObjectLifetimeDefault = lt.res {
err.span_suggestion_verbose(
fn_return.span.shrink_to_hi(),
- &format!(
+ format!(
"{declare} the trait object {captures}, {explicit}",
declare = declare,
captures = captures,
@@ -407,7 +404,7 @@ pub fn suggest_new_region_bound(
if let Some(explicit_static) = &explicit_static {
err.span_suggestion_verbose(
lt.ident.span,
- &format!("{} the trait object's {}", consider, explicit_static),
+ format!("{} the trait object's {}", consider, explicit_static),
&lifetime_name,
Applicability::MaybeIncorrect,
);
diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
index 2875448ee..ce70bcc5c 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs
@@ -13,7 +13,7 @@ use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::RegionHighlightMode;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor};
+use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitor};
use rustc_span::Span;
use std::ops::ControlFlow;
@@ -81,7 +81,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> {
self.highlight.highlighting_region(r, self.counter);
self.counter += 1;
}
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
index b38bbdfe7..421eb807a 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs
@@ -2,6 +2,7 @@ use super::TypeErrCtxt;
use rustc_errors::Applicability::{MachineApplicable, MaybeIncorrect};
use rustc_errors::{pluralize, Diagnostic, MultiSpan};
use rustc_hir as hir;
+use rustc_hir::def::DefKind;
use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::error::ExpectedFound;
use rustc_middle::ty::print::Printer;
@@ -71,9 +72,10 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
#traits-as-parameters",
);
}
- (ty::Alias(ty::Projection, _), ty::Alias(ty::Projection, _)) => {
+ (ty::Alias(ty::Projection | ty::Inherent, _), ty::Alias(ty::Projection | ty::Inherent, _)) => {
diag.note("an associated type was expected, but a different one was found");
}
+ // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
(ty::Param(p), ty::Alias(ty::Projection, proj)) | (ty::Alias(ty::Projection, proj), ty::Param(p))
if !tcx.is_impl_trait_in_trait(proj.def_id) =>
{
@@ -209,7 +211,7 @@ impl<T> Trait<T> for X {
if !sp.contains(p_span) {
diag.span_label(p_span, "this type parameter");
}
- diag.help(&format!(
+ diag.help(format!(
"every closure has a distinct type and so could not always match the \
caller-chosen type of parameter `{}`",
p
@@ -222,7 +224,7 @@ impl<T> Trait<T> for X {
diag.span_label(p_span, "this type parameter");
}
}
- (ty::Alias(ty::Projection, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+ (ty::Alias(ty::Projection | ty::Inherent, proj_ty), _) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
self.expected_projection(
diag,
proj_ty,
@@ -231,7 +233,7 @@ impl<T> Trait<T> for X {
cause.code(),
);
}
- (_, ty::Alias(ty::Projection, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
+ (_, ty::Alias(ty::Projection | ty::Inherent, proj_ty)) if !tcx.is_impl_trait_in_trait(proj_ty.def_id) => {
let msg = format!(
"consider constraining the associated type `{}` to `{}`",
values.found, values.expected,
@@ -248,13 +250,22 @@ impl<T> Trait<T> for X {
proj_ty,
values.expected,
)) {
- diag.help(&msg);
+ diag.help(msg);
diag.note(
"for more information, visit \
https://doc.rust-lang.org/book/ch19-03-advanced-traits.html",
);
}
}
+ (ty::Alias(ty::Opaque, alias), _) | (_, ty::Alias(ty::Opaque, alias)) if alias.def_id.is_local() && matches!(tcx.def_kind(body_owner_def_id), DefKind::AssocFn | DefKind::AssocConst) => {
+ if tcx.is_type_alias_impl_trait(alias.def_id) {
+ if !tcx.opaque_types_defined_by(body_owner_def_id.expect_local()).contains(&alias.def_id.expect_local()) {
+ diag.span_note(tcx.def_span(body_owner_def_id), "\
+ this item must have the opaque type in its signature \
+ in order to be able to register hidden types");
+ }
+ }
+ }
(ty::FnPtr(_), ty::FnDef(def, _))
if let hir::def::DefKind::Fn = tcx.def_kind(def) => {
diag.note(
@@ -415,12 +426,12 @@ impl<T> Trait<T> for X {
if !impl_comparison {
// Generic suggestion when we can't be more specific.
if callable_scope {
- diag.help(&format!(
+ diag.help(format!(
"{} or calling a method that returns `{}`",
msg, values.expected
));
} else {
- diag.help(&msg);
+ diag.help(msg);
}
diag.note(
"for more information, visit \
@@ -462,10 +473,7 @@ fn foo(&self) -> Self::T { String::new() }
if let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = *proj_ty.self_ty().kind() {
let opaque_local_def_id = def_id.as_local();
let opaque_hir_ty = if let Some(opaque_local_def_id) = opaque_local_def_id {
- match &tcx.hir().expect_item(opaque_local_def_id).kind {
- hir::ItemKind::OpaqueTy(opaque_hir_ty) => opaque_hir_ty,
- _ => bug!("The HirId comes from a `ty::Opaque`"),
- }
+ tcx.hir().expect_item(opaque_local_def_id).expect_opaque_ty()
} else {
return false;
};
@@ -539,7 +547,7 @@ fn foo(&self) -> Self::T { String::new() }
for (sp, label) in methods.into_iter() {
span.push_span_label(sp, label);
}
- diag.span_help(span, &msg);
+ diag.span_help(span, msg);
return true;
}
false
diff --git a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
index b5aeca12a..d885d0407 100644
--- a/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
+++ b/compiler/rustc_infer/src/infer/error_reporting/suggest.rs
@@ -1,16 +1,15 @@
use hir::def::CtorKind;
use hir::intravisit::{walk_expr, walk_stmt, Visitor};
use rustc_data_structures::fx::FxIndexSet;
-use rustc_errors::Diagnostic;
+use rustc_errors::{Applicability, Diagnostic};
use rustc_hir as hir;
use rustc_middle::traits::{
IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode,
StatementAsExpression,
};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::{self as ty, IsSuggestable, Ty, TypeVisitableExt};
+use rustc_middle::ty::{self as ty, GenericArgKind, IsSuggestable, Ty, TypeVisitableExt};
use rustc_span::{sym, BytePos, Span};
-use rustc_target::abi::FieldIdx;
use crate::errors::{
ConsiderAddingAwait, FnConsiderCasting, FnItemsAreDistinct, FnUniqTypes,
@@ -114,7 +113,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
variant.fields.len() == 1 && variant.ctor_kind() == Some(CtorKind::Fn)
})
.filter_map(|variant| {
- let sole_field = &variant.fields[FieldIdx::from_u32(0)];
+ let sole_field = &variant.single_field();
let sole_field_ty = sole_field.ty(self.tcx, substs);
if self.same_type_modulo_infer(sole_field_ty, exp_found.found) {
let variant_path =
@@ -536,6 +535,82 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> {
}
None
}
+
+ /// For "one type is more general than the other" errors on closures, suggest changing the lifetime
+ /// of the parameters to accept all lifetimes.
+ pub(super) fn suggest_for_all_lifetime_closure(
+ &self,
+ span: Span,
+ hir: hir::Node<'_>,
+ exp_found: &ty::error::ExpectedFound<ty::PolyTraitRef<'tcx>>,
+ diag: &mut Diagnostic,
+ ) {
+ // 0. Extract fn_decl from hir
+ let hir::Node::Expr(hir::Expr { kind: hir::ExprKind::Closure(hir::Closure { body, fn_decl, .. }), .. }) = hir else { return; };
+ let hir::Body { params, .. } = self.tcx.hir().body(*body);
+
+ // 1. Get the substs of the closure.
+ // 2. Assume exp_found is FnOnce / FnMut / Fn, we can extract function parameters from [1].
+ let Some(expected) = exp_found.expected.skip_binder().substs.get(1) else { return; };
+ let Some(found) = exp_found.found.skip_binder().substs.get(1) else { return; };
+ let expected = expected.unpack();
+ let found = found.unpack();
+ // 3. Extract the tuple type from Fn trait and suggest the change.
+ if let GenericArgKind::Type(expected) = expected &&
+ let GenericArgKind::Type(found) = found &&
+ let ty::Tuple(expected) = expected.kind() &&
+ let ty::Tuple(found)= found.kind() &&
+ expected.len() == found.len() {
+ let mut suggestion = "|".to_string();
+ let mut is_first = true;
+ let mut has_suggestion = false;
+
+ for (((expected, found), param_hir), arg_hir) in expected.iter()
+ .zip(found.iter())
+ .zip(params.iter())
+ .zip(fn_decl.inputs.iter()) {
+ if is_first {
+ is_first = false;
+ } else {
+ suggestion += ", ";
+ }
+
+ if let ty::Ref(expected_region, _, _) = expected.kind() &&
+ let ty::Ref(found_region, _, _) = found.kind() &&
+ expected_region.is_late_bound() &&
+ !found_region.is_late_bound() &&
+ let hir::TyKind::Infer = arg_hir.kind {
+ // If the expected region is late bound, the found region is not, and users are asking compiler
+ // to infer the type, we can suggest adding `: &_`.
+ if param_hir.pat.span == param_hir.ty_span {
+ // for `|x|`, `|_|`, `|x: impl Foo|`
+ let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
+ suggestion += &format!("{}: &_", pat);
+ } else {
+ // for `|x: ty|`, `|_: ty|`
+ let Ok(pat) = self.tcx.sess.source_map().span_to_snippet(param_hir.pat.span) else { return; };
+ let Ok(ty) = self.tcx.sess.source_map().span_to_snippet(param_hir.ty_span) else { return; };
+ suggestion += &format!("{}: &{}", pat, ty);
+ }
+ has_suggestion = true;
+ } else {
+ let Ok(arg) = self.tcx.sess.source_map().span_to_snippet(param_hir.span) else { return; };
+ // Otherwise, keep it as-is.
+ suggestion += &arg;
+ }
+ }
+ suggestion += "|";
+
+ if has_suggestion {
+ diag.span_suggestion_verbose(
+ span,
+ "consider specifying the type of the closure parameters",
+ suggestion,
+ Applicability::MaybeIncorrect,
+ );
+ }
+ }
+ }
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs
index d89f63e5c..0219167f6 100644
--- a/compiler/rustc_infer/src/infer/freshen.rs
+++ b/compiler/rustc_infer/src/infer/freshen.rs
@@ -127,7 +127,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for TypeFreshener<'a, 'tcx> {
#[inline]
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_infer() && !t.has_erasable_regions() {
+ if !t.has_infer() && !t.has_erasable_regions() {
t
} else {
match *t.kind() {
diff --git a/compiler/rustc_infer/src/infer/generalize.rs b/compiler/rustc_infer/src/infer/generalize.rs
new file mode 100644
index 000000000..d4a1dacde
--- /dev/null
+++ b/compiler/rustc_infer/src/infer/generalize.rs
@@ -0,0 +1,479 @@
+use rustc_data_structures::sso::SsoHashMap;
+use rustc_hir::def_id::DefId;
+use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
+use rustc_middle::ty::error::TypeError;
+use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::{self, InferConst, Term, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::Span;
+
+use crate::infer::nll_relate::TypeRelatingDelegate;
+use crate::infer::type_variable::TypeVariableValue;
+use crate::infer::{InferCtxt, RegionVariableOrigin};
+
+/// Attempts to generalize `term` for the type variable `for_vid`.
+/// This checks for cycles -- that is, whether the type `term`
+/// references `for_vid`.
+pub(super) fn generalize<'tcx, D: GeneralizerDelegate<'tcx>, T: Into<Term<'tcx>> + Relate<'tcx>>(
+ infcx: &InferCtxt<'tcx>,
+ delegate: &mut D,
+ term: T,
+ for_vid: impl Into<ty::TermVid<'tcx>>,
+ ambient_variance: ty::Variance,
+) -> RelateResult<'tcx, Generalization<T>> {
+ let (for_universe, root_vid) = match for_vid.into() {
+ ty::TermVid::Ty(ty_vid) => (
+ infcx.probe_ty_var(ty_vid).unwrap_err(),
+ ty::TermVid::Ty(infcx.inner.borrow_mut().type_variables().sub_root_var(ty_vid)),
+ ),
+ ty::TermVid::Const(ct_vid) => (
+ infcx.probe_const_var(ct_vid).unwrap_err(),
+ ty::TermVid::Const(infcx.inner.borrow_mut().const_unification_table().find(ct_vid)),
+ ),
+ };
+
+ let mut generalizer = Generalizer {
+ infcx,
+ delegate,
+ ambient_variance,
+ root_vid,
+ for_universe,
+ root_term: term.into(),
+ needs_wf: false,
+ cache: Default::default(),
+ };
+
+ assert!(!term.has_escaping_bound_vars());
+ let value = generalizer.relate(term, term)?;
+ let needs_wf = generalizer.needs_wf;
+ Ok(Generalization { value, needs_wf })
+}
+
+/// Abstracts the handling of region vars between HIR and MIR/NLL typechecking
+/// in the generalizer code.
+pub trait GeneralizerDelegate<'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx>;
+
+ fn forbid_inference_vars() -> bool;
+
+ fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx>;
+}
+
+pub struct CombineDelegate<'cx, 'tcx> {
+ pub infcx: &'cx InferCtxt<'tcx>,
+ pub param_env: ty::ParamEnv<'tcx>,
+ pub span: Span,
+}
+
+impl<'tcx> GeneralizerDelegate<'tcx> for CombineDelegate<'_, 'tcx> {
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.param_env
+ }
+
+ fn forbid_inference_vars() -> bool {
+ false
+ }
+
+ fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
+ // FIXME: This is non-ideal because we don't give a
+ // very descriptive origin for this region variable.
+ self.infcx
+ .next_region_var_in_universe(RegionVariableOrigin::MiscVariable(self.span), universe)
+ }
+}
+
+impl<'tcx, T> GeneralizerDelegate<'tcx> for T
+where
+ T: TypeRelatingDelegate<'tcx>,
+{
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ <Self as TypeRelatingDelegate<'tcx>>::param_env(self)
+ }
+
+ fn forbid_inference_vars() -> bool {
+ <Self as TypeRelatingDelegate<'tcx>>::forbid_inference_vars()
+ }
+
+ fn generalize_region(&mut self, universe: ty::UniverseIndex) -> ty::Region<'tcx> {
+ <Self as TypeRelatingDelegate<'tcx>>::generalize_existential(self, universe)
+ }
+}
+
+/// The "generalizer" is used when handling inference variables.
+///
+/// The basic strategy for handling a constraint like `?A <: B` is to
+/// apply a "generalization strategy" to the term `B` -- this replaces
+/// all the lifetimes in the term `B` with fresh inference variables.
+/// (You can read more about the strategy in this [blog post].)
+///
+/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
+/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
+/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
+/// establishes `'0: 'x` as a constraint.
+///
+/// [blog post]: https://is.gd/0hKvIr
+struct Generalizer<'me, 'tcx, D> {
+ infcx: &'me InferCtxt<'tcx>,
+
+ /// This is used to abstract the behaviors of the three previous
+ /// generalizer-like implementations (`Generalizer`, `TypeGeneralizer`,
+ /// and `ConstInferUnifier`). See [`GeneralizerDelegate`] for more
+ /// information.
+ delegate: &'me mut D,
+
+ /// After we generalize this type, we are going to relate it to
+ /// some other type. What will be the variance at this point?
+ ambient_variance: ty::Variance,
+
+ /// The vid of the type variable that is in the process of being
+ /// instantiated. If we find this within the value we are folding,
+ /// that means we would have created a cyclic value.
+ root_vid: ty::TermVid<'tcx>,
+
+ /// The universe of the type variable that is in the process of being
+ /// instantiated. If we find anything that this universe cannot name,
+ /// we reject the relation.
+ for_universe: ty::UniverseIndex,
+
+ /// The root term (const or type) we're generalizing. Used for cycle errors.
+ root_term: Term<'tcx>,
+
+ cache: SsoHashMap<Ty<'tcx>, Ty<'tcx>>,
+
+ /// See the field `needs_wf` in `Generalization`.
+ needs_wf: bool,
+}
+
+impl<'tcx, D> Generalizer<'_, 'tcx, D> {
+ /// Create an error that corresponds to the term kind in `root_term`
+ fn cyclic_term_error(&self) -> TypeError<'tcx> {
+ match self.root_term.unpack() {
+ ty::TermKind::Ty(ty) => TypeError::CyclicTy(ty),
+ ty::TermKind::Const(ct) => TypeError::CyclicConst(ct),
+ }
+ }
+}
+
+impl<'tcx, D> TypeRelation<'tcx> for Generalizer<'_, 'tcx, D>
+where
+ D: GeneralizerDelegate<'tcx>,
+{
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.infcx.tcx
+ }
+
+ fn param_env(&self) -> ty::ParamEnv<'tcx> {
+ self.delegate.param_env()
+ }
+
+ fn tag(&self) -> &'static str {
+ "Generalizer"
+ }
+
+ fn a_is_expected(&self) -> bool {
+ true
+ }
+
+ fn relate_item_substs(
+ &mut self,
+ item_def_id: DefId,
+ a_subst: ty::SubstsRef<'tcx>,
+ b_subst: ty::SubstsRef<'tcx>,
+ ) -> RelateResult<'tcx, ty::SubstsRef<'tcx>> {
+ if self.ambient_variance == ty::Variance::Invariant {
+ // Avoid fetching the variance if we are in an invariant
+ // context; no need, and it can induce dependency cycles
+ // (e.g., #41849).
+ relate::relate_substs(self, a_subst, b_subst)
+ } else {
+ let tcx = self.tcx();
+ let opt_variances = tcx.variances_of(item_def_id);
+ relate::relate_substs_with_variances(
+ self,
+ item_def_id,
+ opt_variances,
+ a_subst,
+ b_subst,
+ true,
+ )
+ }
+ }
+
+ #[instrument(level = "debug", skip(self, variance, b), ret)]
+ fn relate_with_variance<T: Relate<'tcx>>(
+ &mut self,
+ variance: ty::Variance,
+ _info: ty::VarianceDiagInfo<'tcx>,
+ a: T,
+ b: T,
+ ) -> RelateResult<'tcx, T> {
+ let old_ambient_variance = self.ambient_variance;
+ self.ambient_variance = self.ambient_variance.xform(variance);
+ debug!(?self.ambient_variance, "new ambient variance");
+ let r = self.relate(a, b)?;
+ self.ambient_variance = old_ambient_variance;
+ Ok(r)
+ }
+
+ #[instrument(level = "debug", skip(self, t2), ret)]
+ fn tys(&mut self, t: Ty<'tcx>, t2: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
+ assert_eq!(t, t2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ if let Some(&result) = self.cache.get(&t) {
+ return Ok(result);
+ }
+
+ // Check to see whether the type we are generalizing references
+ // any other type variable related to `vid` via
+ // subtyping. This is basically our "occurs check", preventing
+ // us from creating infinitely sized types.
+ let g = match *t.kind() {
+ ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
+ if D::forbid_inference_vars() =>
+ {
+ bug!("unexpected inference variable encountered in NLL generalization: {t}");
+ }
+
+ ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ bug!("unexpected infer type: {t}")
+ }
+
+ ty::Infer(ty::TyVar(vid)) => {
+ let mut inner = self.infcx.inner.borrow_mut();
+ let vid = inner.type_variables().root_var(vid);
+ let sub_vid = inner.type_variables().sub_root_var(vid);
+
+ if ty::TermVid::Ty(sub_vid) == self.root_vid {
+ // If sub-roots are equal, then `root_vid` and
+ // `vid` are related via subtyping.
+ Err(self.cyclic_term_error())
+ } else {
+ let probe = inner.type_variables().probe(vid);
+ match probe {
+ TypeVariableValue::Known { value: u } => {
+ drop(inner);
+ self.relate(u, u)
+ }
+ TypeVariableValue::Unknown { universe } => {
+ match self.ambient_variance {
+ // Invariant: no need to make a fresh type variable
+ // if we can name the universe.
+ ty::Invariant => {
+ if self.for_universe.can_name(universe) {
+ return Ok(t);
+ }
+ }
+
+ // Bivariant: make a fresh var, but we
+ // may need a WF predicate. See
+ // comment on `needs_wf` field for
+ // more info.
+ ty::Bivariant => self.needs_wf = true,
+
+ // Co/contravariant: this will be
+ // sufficiently constrained later on.
+ ty::Covariant | ty::Contravariant => (),
+ }
+
+ let origin = *inner.type_variables().var_origin(vid);
+ let new_var_id =
+ inner.type_variables().new_var(self.for_universe, origin);
+ let u = self.tcx().mk_ty_var(new_var_id);
+
+ // Record that we replaced `vid` with `new_var_id` as part of a generalization
+ // operation. This is needed to detect cyclic types. To see why, see the
+ // docs in the `type_variables` module.
+ inner.type_variables().sub(vid, new_var_id);
+ debug!("replacing original vid={:?} with new={:?}", vid, u);
+ Ok(u)
+ }
+ }
+ }
+ }
+
+ ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
+ // No matter what mode we are in,
+ // integer/floating-point types must be equal to be
+ // relatable.
+ Ok(t)
+ }
+
+ ty::Placeholder(placeholder) => {
+ if self.for_universe.can_name(placeholder.universe) {
+ Ok(t)
+ } else {
+ debug!(
+ "root universe {:?} cannot name placeholder in universe {:?}",
+ self.for_universe, placeholder.universe
+ );
+ Err(TypeError::Mismatch)
+ }
+ }
+
+ _ => relate::structurally_relate_tys(self, t, t),
+ }?;
+
+ self.cache.insert(t, g);
+ Ok(g)
+ }
+
+ #[instrument(level = "debug", skip(self, r2), ret)]
+ fn regions(
+ &mut self,
+ r: ty::Region<'tcx>,
+ r2: ty::Region<'tcx>,
+ ) -> RelateResult<'tcx, ty::Region<'tcx>> {
+ assert_eq!(r, r2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ match *r {
+ // Never make variables for regions bound within the type itself,
+ // nor for erased regions.
+ ty::ReLateBound(..) | ty::ReErased => {
+ return Ok(r);
+ }
+
+ // It doesn't really matter for correctness if we generalize ReError,
+ // since we're already on a doomed compilation path.
+ ty::ReError(_) => {
+ return Ok(r);
+ }
+
+ ty::RePlaceholder(..)
+ | ty::ReVar(..)
+ | ty::ReStatic
+ | ty::ReEarlyBound(..)
+ | ty::ReFree(..) => {
+ // see common code below
+ }
+ }
+
+ // If we are in an invariant context, we can re-use the region
+ // as is, unless it happens to be in some universe that we
+ // can't name.
+ if let ty::Invariant = self.ambient_variance {
+ let r_universe = self.infcx.universe_of_region(r);
+ if self.for_universe.can_name(r_universe) {
+ return Ok(r);
+ }
+ }
+
+ Ok(self.delegate.generalize_region(self.for_universe))
+ }
+
+ #[instrument(level = "debug", skip(self, c2), ret)]
+ fn consts(
+ &mut self,
+ c: ty::Const<'tcx>,
+ c2: ty::Const<'tcx>,
+ ) -> RelateResult<'tcx, ty::Const<'tcx>> {
+ assert_eq!(c, c2); // we are misusing TypeRelation here; both LHS and RHS ought to be ==
+
+ match c.kind() {
+ ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
+ bug!("unexpected inference variable encountered in NLL generalization: {:?}", c);
+ }
+ ty::ConstKind::Infer(InferConst::Var(vid)) => {
+ // If root const vids are equal, then `root_vid` and
+ // `vid` are related and we'd be inferring an infinitely
+ // deep const.
+ if ty::TermVid::Const(
+ self.infcx.inner.borrow_mut().const_unification_table().find(vid),
+ ) == self.root_vid
+ {
+ return Err(self.cyclic_term_error());
+ }
+
+ let mut inner = self.infcx.inner.borrow_mut();
+ let variable_table = &mut inner.const_unification_table();
+ let var_value = variable_table.probe_value(vid);
+ match var_value.val {
+ ConstVariableValue::Known { value: u } => {
+ drop(inner);
+ self.relate(u, u)
+ }
+ ConstVariableValue::Unknown { universe } => {
+ if self.for_universe.can_name(universe) {
+ Ok(c)
+ } else {
+ let new_var_id = variable_table.new_key(ConstVarValue {
+ origin: var_value.origin,
+ val: ConstVariableValue::Unknown { universe: self.for_universe },
+ });
+ Ok(self.tcx().mk_const(new_var_id, c.ty()))
+ }
+ }
+ }
+ }
+ // FIXME: remove this branch once `structurally_relate_consts` is fully
+ // structural.
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
+ let substs = self.relate_with_variance(
+ ty::Variance::Invariant,
+ ty::VarianceDiagInfo::default(),
+ substs,
+ substs,
+ )?;
+ Ok(self.tcx().mk_const(ty::UnevaluatedConst { def, substs }, c.ty()))
+ }
+ ty::ConstKind::Placeholder(placeholder) => {
+ if self.for_universe.can_name(placeholder.universe) {
+ Ok(c)
+ } else {
+ debug!(
+ "root universe {:?} cannot name placeholder in universe {:?}",
+ self.for_universe, placeholder.universe
+ );
+ Err(TypeError::Mismatch)
+ }
+ }
+ _ => relate::structurally_relate_consts(self, c, c),
+ }
+ }
+
+ #[instrument(level = "debug", skip(self), ret)]
+ fn binders<T>(
+ &mut self,
+ a: ty::Binder<'tcx, T>,
+ _: ty::Binder<'tcx, T>,
+ ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
+ where
+ T: Relate<'tcx>,
+ {
+ let result = self.relate(a.skip_binder(), a.skip_binder())?;
+ Ok(a.rebind(result))
+ }
+}
+
+/// Result from a generalization operation. This includes
+/// not only the generalized type, but also a bool flag
+/// indicating whether further WF checks are needed.
+#[derive(Debug)]
+pub struct Generalization<T> {
+ pub value: T,
+
+ /// If true, then the generalized type may not be well-formed,
+ /// even if the source type is well-formed, so we should add an
+ /// additional check to enforce that it is. This arises in
+ /// particular around 'bivariant' type parameters that are only
+ /// constrained by a where-clause. As an example, imagine a type:
+ ///
+ /// struct Foo<A, B> where A: Iterator<Item = B> {
+ /// data: A
+ /// }
+ ///
+ /// here, `A` will be covariant, but `B` is
+ /// unconstrained. However, whatever it is, for `Foo` to be WF, it
+ /// must be equal to `A::Item`. If we have an input `Foo<?A, ?B>`,
+ /// then after generalization we will wind up with a type like
+ /// `Foo<?C, ?D>`. When we enforce that `Foo<?A, ?B> <: Foo<?C,
+ /// ?D>` (or `>:`), we will wind up with the requirement that `?A
+ /// <: ?C`, but no particular relationship between `?B` and `?D`
+ /// (after all, we do not know the variance of the normalized form
+ /// of `A::Item` with respect to `A`). If we do nothing else, this
+ /// may mean that `?D` goes unconstrained (as in #41677). So, in
+ /// this scenario where we create a new type variable in a
+ /// bivariant context, we set the `needs_wf` flag to true. This
+ /// will force the calling code to check that `WF(Foo<?C, ?D>)`
+ /// holds, which in turn implies that `?C::Item == ?D`. So once
+ /// `?C` is constrained, that should suffice to restrict `?D`.
+ pub needs_wf: bool,
+}
diff --git a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
index a63cfbc91..c304cd25c 100644
--- a/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
+++ b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs
@@ -42,7 +42,7 @@ impl<'a, 'tcx> CombineFields<'a, 'tcx> {
// Next, we instantiate each bound region in the subtype
// with a fresh region variable. These region variables --
- // but no other pre-existing region variables -- can name
+ // but no other preexisting region variables -- can name
// the placeholders.
let sub_prime = self.infcx.instantiate_binder_with_fresh_vars(span, HigherRankedType, sub);
diff --git a/compiler/rustc_infer/src/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs
index 7f4c141b9..7190d33d2 100644
--- a/compiler/rustc_infer/src/infer/lattice.rs
+++ b/compiler/rustc_infer/src/infer/lattice.rs
@@ -108,9 +108,12 @@ where
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
) if a_def_id == b_def_id => infcx.super_combine_tys(this, a, b),
+
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if this.define_opaque_types() == DefineOpaqueTypes::Yes && def_id.is_local() =>
+ if this.define_opaque_types() == DefineOpaqueTypes::Yes
+ && def_id.is_local()
+ && !this.tcx().trait_solver_next() =>
{
this.register_obligations(
infcx
diff --git a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
index f298b95ca..8482ae2aa 100644
--- a/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
+++ b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs
@@ -13,7 +13,7 @@ use rustc_data_structures::graph::implementation::{
Direction, Graph, NodeIndex, INCOMING, OUTGOING,
};
use rustc_data_structures::intern::Interned;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::PlaceholderRegion;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -102,6 +102,17 @@ pub enum RegionResolutionError<'tcx> {
),
}
+impl<'tcx> RegionResolutionError<'tcx> {
+ pub fn origin(&self) -> &SubregionOrigin<'tcx> {
+ match self {
+ RegionResolutionError::ConcreteFailure(origin, _, _)
+ | RegionResolutionError::GenericBoundFailure(origin, _, _)
+ | RegionResolutionError::SubSupConflict(_, _, origin, _, _, _, _)
+ | RegionResolutionError::UpperBoundUniverseConflict(_, _, _, origin, _) => origin,
+ }
+ }
+}
+
struct RegionAndOrigin<'tcx> {
region: Region<'tcx>,
origin: SubregionOrigin<'tcx>,
@@ -131,10 +142,9 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
self.dump_constraints();
}
- let graph = self.construct_graph();
self.expansion(&mut var_data);
self.collect_errors(&mut var_data, errors);
- self.collect_var_errors(&var_data, &graph, errors);
+ self.collect_var_errors(&var_data, errors);
var_data
}
@@ -622,7 +632,6 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
fn collect_var_errors(
&self,
var_data: &LexicalRegionResolutions<'tcx>,
- graph: &RegionGraph<'tcx>,
errors: &mut Vec<RegionResolutionError<'tcx>>,
) {
debug!("collect_var_errors, var_data = {:#?}", var_data.values);
@@ -640,6 +649,10 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// overlapping locations.
let mut dup_vec = IndexVec::from_elem_n(None, self.num_vars());
+ // Only construct the graph when necessary, because it's moderately
+ // expensive.
+ let mut graph = None;
+
for (node_vid, value) in var_data.values.iter_enumerated() {
match *value {
VarValue::Empty(_) | VarValue::Value(_) => { /* Inference successful */ }
@@ -672,7 +685,8 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// influence the constraints on this value for
// richer diagnostics in `static_impl_trait`.
- self.collect_error_for_expanding_node(graph, &mut dup_vec, node_vid, errors);
+ let g = graph.get_or_insert_with(|| self.construct_graph());
+ self.collect_error_for_expanding_node(g, &mut dup_vec, node_vid, errors);
}
}
}
@@ -821,7 +835,7 @@ impl<'cx, 'tcx> LexicalResolver<'cx, 'tcx> {
// resolution errors here; delay ICE in favor of those errors.
self.tcx().sess.delay_span_bug(
self.var_infos[node_idx].origin.span(),
- &format!(
+ format!(
"collect_error_for_expanding_node() could not find \
error for var {:?} in universe {:?}, lower_bounds={:#?}, \
upper_bounds={:#?}",
diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs
index 66f51328b..cd99fc312 100644
--- a/compiler/rustc_infer/src/infer/mod.rs
+++ b/compiler/rustc_infer/src/infer/mod.rs
@@ -24,7 +24,7 @@ use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue};
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType};
use rustc_middle::mir::interpret::{ErrorHandled, EvalToValTreeResult};
use rustc_middle::mir::ConstraintCategory;
-use rustc_middle::traits::select;
+use rustc_middle::traits::{select, DefiningAnchor};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BoundVarReplacerDelegate;
use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
@@ -39,7 +39,6 @@ use rustc_span::Span;
use std::cell::{Cell, RefCell};
use std::fmt;
-use std::ops::Drop;
use self::combine::CombineFields;
use self::error_reporting::TypeErrCtxt;
@@ -59,6 +58,7 @@ pub mod error_reporting;
pub mod free_regions;
mod freshen;
mod fudge;
+mod generalize;
mod glb;
mod higher_ranked;
pub mod lattice;
@@ -231,17 +231,6 @@ impl<'tcx> InferCtxtInner<'tcx> {
}
}
-#[derive(Clone, Copy, Debug, PartialEq, Eq)]
-pub enum DefiningAnchor {
- /// `DefId` of the item.
- Bind(LocalDefId),
- /// When opaque types are not resolved, we `Bubble` up, meaning
- /// return the opaque/hidden type pair from query, for caller of query to handle it.
- Bubble,
- /// Used to catch type mismatch errors when handling opaque types.
- Error,
-}
-
pub struct InferCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
@@ -342,11 +331,6 @@ pub struct InferCtxt<'tcx> {
/// there is no type that the user could *actually name* that
/// would satisfy it. This avoids crippling inference, basically.
pub intercrate: bool,
-
- /// Flag that is set when we enter canonicalization. Used for debugging to ensure
- /// that we only collect region information for `BorrowckInferCtxt::reg_var_to_origin`
- /// inside non-canonicalization contexts.
- inside_canonicalization_ctxt: Cell<bool>,
}
/// See the `error_reporting` module for more details.
@@ -638,7 +622,6 @@ impl<'tcx> InferCtxtBuilder<'tcx> {
skip_leak_check: Cell::new(false),
universe: Cell::new(ty::UniverseIndex::ROOT),
intercrate,
- inside_canonicalization_ctxt: Cell::new(false),
}
}
}
@@ -1228,11 +1211,11 @@ impl<'tcx> InferCtxt<'tcx> {
/// hence that `resolve_regions_and_report_errors` can never be
/// called. This is used only during NLL processing to "hand off" ownership
/// of the set of region variables into the NLL region context.
- pub fn take_region_var_origins(&self) -> VarInfos {
+ pub fn get_region_var_origins(&self) -> VarInfos {
let mut inner = self.inner.borrow_mut();
let (var_infos, data) = inner
.region_constraint_storage
- .take()
+ .clone()
.expect("regions already resolved")
.with_log(&mut inner.undo_log)
.into_infos_and_data();
@@ -1327,7 +1310,7 @@ impl<'tcx> InferCtxt<'tcx> {
where
T: TypeFoldable<TyCtxt<'tcx>>,
{
- if !value.needs_infer() {
+ if !value.has_infer() {
return value; // Avoid duplicated subst-folding.
}
let mut r = InferenceLiteralEraser { tcx: self.tcx };
@@ -1365,7 +1348,7 @@ impl<'tcx> InferCtxt<'tcx> {
pub fn fully_resolve<T: TypeFoldable<TyCtxt<'tcx>>>(&self, value: T) -> FixupResult<'tcx, T> {
let value = resolve::fully_resolve(self, value);
assert!(
- value.as_ref().map_or(true, |value| !value.needs_infer()),
+ value.as_ref().map_or(true, |value| !value.has_infer()),
"`{value:?}` is not fully resolved"
);
value
@@ -1500,7 +1483,7 @@ impl<'tcx> InferCtxt<'tcx> {
Ok(Some(val)) => Ok(self.tcx.mk_const(val, ty)),
Ok(None) => {
let tcx = self.tcx;
- let def_id = unevaluated.def.did;
+ let def_id = unevaluated.def;
span_bug!(
tcx.def_span(def_id),
"unable to construct a constant value for the unevaluated constant {:?}",
@@ -1537,18 +1520,18 @@ impl<'tcx> InferCtxt<'tcx> {
// variables
let tcx = self.tcx;
if substs.has_non_region_infer() {
- if let Some(ct) = tcx.bound_abstract_const(unevaluated.def)? {
+ if let Some(ct) = tcx.thir_abstract_const(unevaluated.def)? {
let ct = tcx.expand_abstract_consts(ct.subst(tcx, substs));
if let Err(e) = ct.error_reported() {
- return Err(ErrorHandled::Reported(e));
+ return Err(ErrorHandled::Reported(e.into()));
} else if ct.has_non_region_infer() || ct.has_non_region_param() {
return Err(ErrorHandled::TooGeneric);
} else {
substs = replace_param_and_infer_substs_with_placeholder(tcx, substs);
}
} else {
- substs = InternalSubsts::identity_for_item(tcx, unevaluated.def.did);
- param_env = tcx.param_env(unevaluated.def.did);
+ substs = InternalSubsts::identity_for_item(tcx, unevaluated.def);
+ param_env = tcx.param_env(unevaluated.def);
}
}
@@ -1577,10 +1560,10 @@ impl<'tcx> InferCtxt<'tcx> {
(TyOrConstInferVar::Ty(ty_var), Ok(inner)) => {
use self::type_variable::TypeVariableValue;
- match inner.try_type_variables_probe_ref(ty_var) {
- Some(TypeVariableValue::Unknown { .. }) => true,
- _ => false,
- }
+ matches!(
+ inner.try_type_variables_probe_ref(ty_var),
+ Some(TypeVariableValue::Unknown { .. })
+ )
}
_ => false,
};
@@ -1636,31 +1619,6 @@ impl<'tcx> InferCtxt<'tcx> {
}
}
}
-
- pub fn inside_canonicalization_ctxt(&self) -> bool {
- self.inside_canonicalization_ctxt.get()
- }
-
- pub fn set_canonicalization_ctxt(&self) -> CanonicalizationCtxtGuard<'_, 'tcx> {
- let prev_ctxt = self.inside_canonicalization_ctxt();
- self.inside_canonicalization_ctxt.set(true);
- CanonicalizationCtxtGuard { prev_ctxt, infcx: self }
- }
-
- fn set_canonicalization_ctxt_to(&self, ctxt: bool) {
- self.inside_canonicalization_ctxt.set(ctxt);
- }
-}
-
-pub struct CanonicalizationCtxtGuard<'cx, 'tcx> {
- prev_ctxt: bool,
- infcx: &'cx InferCtxt<'tcx>,
-}
-
-impl<'cx, 'tcx> Drop for CanonicalizationCtxtGuard<'cx, 'tcx> {
- fn drop(&mut self) {
- self.infcx.set_canonicalization_ctxt_to(self.prev_ctxt)
- }
}
impl<'tcx> TypeErrCtxt<'_, 'tcx> {
diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
index 9f7b26b87..d3fd01b96 100644
--- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs
+++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs
@@ -21,22 +21,20 @@
//! thing we relate in chalk are basically domain goals and their
//! constituents)
-use crate::infer::InferCtxt;
-use crate::infer::{ConstVarValue, ConstVariableValue};
-use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
-use crate::traits::{Obligation, PredicateObligations};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::traits::ObligationCause;
-use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::fold::FnMutDelegate;
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor};
+use rustc_middle::ty::relate::{Relate, RelateResult, TypeRelation};
+use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::{self, InferConst, Ty, TyCtxt};
use rustc_span::{Span, Symbol};
use std::fmt::Debug;
-use std::ops::ControlFlow;
-use super::combine::ObligationEmittingRelation;
+use crate::infer::combine::ObligationEmittingRelation;
+use crate::infer::generalize::{self, Generalization};
+use crate::infer::InferCtxt;
+use crate::infer::{TypeVariableOrigin, TypeVariableOriginKind};
+use crate::traits::{Obligation, PredicateObligations};
pub struct TypeRelating<'me, 'tcx, D>
where
@@ -115,11 +113,6 @@ pub trait TypeRelatingDelegate<'tcx> {
fn forbid_inference_vars() -> bool;
}
-#[derive(Clone, Debug, Default)]
-struct BoundRegionScope<'tcx> {
- map: FxHashMap<ty::BoundRegion, ty::Region<'tcx>>,
-}
-
#[derive(Copy, Clone)]
struct UniversallyQuantified(bool);
@@ -204,7 +197,7 @@ where
_ => (),
}
- let generalized_ty = self.generalize_value(value_ty, vid)?;
+ let generalized_ty = self.generalize(value_ty, vid)?;
debug!("relate_ty_var: generalized_ty = {:?}", generalized_ty);
if D::forbid_inference_vars() {
@@ -223,23 +216,15 @@ where
result
}
- fn generalize_value<T: Relate<'tcx>>(
- &mut self,
- value: T,
- for_vid: ty::TyVid,
- ) -> RelateResult<'tcx, T> {
- let universe = self.infcx.probe_ty_var(for_vid).unwrap_err();
-
- let mut generalizer = TypeGeneralizer {
- infcx: self.infcx,
- delegate: &mut self.delegate,
- first_free_index: ty::INNERMOST,
- ambient_variance: self.ambient_variance,
- for_vid_sub_root: self.infcx.inner.borrow_mut().type_variables().sub_root_var(for_vid),
- universe,
- };
-
- generalizer.relate(value, value)
+ fn generalize(&mut self, ty: Ty<'tcx>, for_vid: ty::TyVid) -> RelateResult<'tcx, Ty<'tcx>> {
+ let Generalization { value: ty, needs_wf: _ } = generalize::generalize(
+ self.infcx,
+ &mut self.delegate,
+ ty,
+ for_vid,
+ self.ambient_variance,
+ )?;
+ Ok(ty)
}
fn relate_opaques(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
@@ -488,13 +473,7 @@ where
}
if a == b {
- // Subtle: if a or b has a bound variable that we are lazily
- // substituting, then even if a == b, it could be that the values we
- // will substitute for those bound variables are *not* the same, and
- // hence returning `Ok(a)` is incorrect.
- if !a.has_escaping_bound_vars() && !b.has_escaping_bound_vars() {
- return Ok(a);
- }
+ return Ok(a);
}
match (a.kind(), b.kind()) {
@@ -512,16 +491,22 @@ where
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, .. }),
- ) if a_def_id == b_def_id => infcx.super_combine_tys(self, a, b).or_else(|err| {
- self.tcx().sess.delay_span_bug(
- self.delegate.span(),
- "failure to relate an opaque to itself should result in an error later on",
- );
- if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
- }),
+ ) if a_def_id == b_def_id || infcx.tcx.trait_solver_next() => {
+ infcx.super_combine_tys(self, a, b).or_else(|err| {
+ // This behavior is only there for the old solver, the new solver
+ // shouldn't ever fail. Instead, it unconditionally emits an
+ // alias-relate goal.
+ assert!(!self.tcx().trait_solver_next());
+ self.tcx().sess.delay_span_bug(
+ self.delegate.span(),
+ "failure to relate an opaque to itself should result in an error later on",
+ );
+ if a_def_id.is_local() { self.relate_opaques(a, b) } else { Err(err) }
+ })
+ }
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
- if def_id.is_local() =>
+ if def_id.is_local() && !self.tcx().trait_solver_next() =>
{
self.relate_opaques(a, b)
}
@@ -725,287 +710,3 @@ where
})]);
}
}
-
-/// When we encounter a binder like `for<..> fn(..)`, we actually have
-/// to walk the `fn` value to find all the values bound by the `for`
-/// (these are not explicitly present in the ty representation right
-/// now). This visitor handles that: it descends the type, tracking
-/// binder depth, and finds late-bound regions targeting the
-/// `for<..`>. For each of those, it creates an entry in
-/// `bound_region_scope`.
-struct ScopeInstantiator<'me, 'tcx> {
- next_region: &'me mut dyn FnMut(ty::BoundRegion) -> ty::Region<'tcx>,
- // The debruijn index of the scope we are instantiating.
- target_index: ty::DebruijnIndex,
- bound_region_scope: &'me mut BoundRegionScope<'tcx>,
-}
-
-impl<'me, 'tcx> TypeVisitor<TyCtxt<'tcx>> for ScopeInstantiator<'me, 'tcx> {
- fn visit_binder<T: TypeVisitable<TyCtxt<'tcx>>>(
- &mut self,
- t: &ty::Binder<'tcx, T>,
- ) -> ControlFlow<Self::BreakTy> {
- self.target_index.shift_in(1);
- t.super_visit_with(self);
- self.target_index.shift_out(1);
-
- ControlFlow::Continue(())
- }
-
- fn visit_region(&mut self, r: ty::Region<'tcx>) -> ControlFlow<Self::BreakTy> {
- let ScopeInstantiator { bound_region_scope, next_region, .. } = self;
-
- match *r {
- ty::ReLateBound(debruijn, br) if debruijn == self.target_index => {
- bound_region_scope.map.entry(br).or_insert_with(|| next_region(br));
- }
-
- _ => {}
- }
-
- ControlFlow::Continue(())
- }
-}
-
-/// The "type generalizer" is used when handling inference variables.
-///
-/// The basic strategy for handling a constraint like `?A <: B` is to
-/// apply a "generalization strategy" to the type `B` -- this replaces
-/// all the lifetimes in the type `B` with fresh inference
-/// variables. (You can read more about the strategy in this [blog
-/// post].)
-///
-/// As an example, if we had `?A <: &'x u32`, we would generalize `&'x
-/// u32` to `&'0 u32` where `'0` is a fresh variable. This becomes the
-/// value of `A`. Finally, we relate `&'0 u32 <: &'x u32`, which
-/// establishes `'0: 'x` as a constraint.
-///
-/// As a side-effect of this generalization procedure, we also replace
-/// all the bound regions that we have traversed with concrete values,
-/// so that the resulting generalized type is independent from the
-/// scopes.
-///
-/// [blog post]: https://is.gd/0hKvIr
-struct TypeGeneralizer<'me, 'tcx, D>
-where
- D: TypeRelatingDelegate<'tcx>,
-{
- infcx: &'me InferCtxt<'tcx>,
-
- delegate: &'me mut D,
-
- /// After we generalize this type, we are going to relate it to
- /// some other type. What will be the variance at this point?
- ambient_variance: ty::Variance,
-
- first_free_index: ty::DebruijnIndex,
-
- /// The vid of the type variable that is in the process of being
- /// instantiated. If we find this within the value we are folding,
- /// that means we would have created a cyclic value.
- for_vid_sub_root: ty::TyVid,
-
- /// The universe of the type variable that is in the process of being
- /// instantiated. If we find anything that this universe cannot name,
- /// we reject the relation.
- universe: ty::UniverseIndex,
-}
-
-impl<'tcx, D> TypeRelation<'tcx> for TypeGeneralizer<'_, 'tcx, D>
-where
- D: TypeRelatingDelegate<'tcx>,
-{
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.delegate.param_env()
- }
-
- fn tag(&self) -> &'static str {
- "nll::generalizer"
- }
-
- fn a_is_expected(&self) -> bool {
- true
- }
-
- fn relate_with_variance<T: Relate<'tcx>>(
- &mut self,
- variance: ty::Variance,
- _info: ty::VarianceDiagInfo<'tcx>,
- a: T,
- b: T,
- ) -> RelateResult<'tcx, T> {
- debug!(
- "TypeGeneralizer::relate_with_variance(variance={:?}, a={:?}, b={:?})",
- variance, a, b
- );
-
- let old_ambient_variance = self.ambient_variance;
- self.ambient_variance = self.ambient_variance.xform(variance);
-
- debug!(
- "TypeGeneralizer::relate_with_variance: ambient_variance = {:?}",
- self.ambient_variance
- );
-
- let r = self.relate(a, b)?;
-
- self.ambient_variance = old_ambient_variance;
-
- debug!("TypeGeneralizer::relate_with_variance: r={:?}", r);
-
- Ok(r)
- }
-
- fn tys(&mut self, a: Ty<'tcx>, _: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- use crate::infer::type_variable::TypeVariableValue;
-
- debug!("TypeGeneralizer::tys(a={:?})", a);
-
- match *a.kind() {
- ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_))
- if D::forbid_inference_vars() =>
- {
- bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
- }
-
- ty::Infer(ty::TyVar(vid)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let variables = &mut inner.type_variables();
- let vid = variables.root_var(vid);
- let sub_vid = variables.sub_root_var(vid);
- if sub_vid == self.for_vid_sub_root {
- // If sub-roots are equal, then `for_vid` and
- // `vid` are related via subtyping.
- debug!("TypeGeneralizer::tys: occurs check failed");
- Err(TypeError::Mismatch)
- } else {
- match variables.probe(vid) {
- TypeVariableValue::Known { value: u } => {
- drop(variables);
- self.relate(u, u)
- }
- TypeVariableValue::Unknown { universe: _universe } => {
- if self.ambient_variance == ty::Bivariant {
- // FIXME: we may need a WF predicate (related to #54105).
- }
-
- let origin = *variables.var_origin(vid);
-
- // Replacing with a new variable in the universe `self.universe`,
- // it will be unified later with the original type variable in
- // the universe `_universe`.
- let new_var_id = variables.new_var(self.universe, origin);
-
- let u = self.tcx().mk_ty_var(new_var_id);
- debug!("generalize: replacing original vid={:?} with new={:?}", vid, u);
- Ok(u)
- }
- }
- }
- }
-
- ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) => {
- // No matter what mode we are in,
- // integer/floating-point types must be equal to be
- // relatable.
- Ok(a)
- }
-
- ty::Placeholder(placeholder) => {
- if self.universe.cannot_name(placeholder.universe) {
- debug!(
- "TypeGeneralizer::tys: root universe {:?} cannot name\
- placeholder in universe {:?}",
- self.universe, placeholder.universe
- );
- Err(TypeError::Mismatch)
- } else {
- Ok(a)
- }
- }
-
- _ => relate::super_relate_tys(self, a, a),
- }
- }
-
- fn regions(
- &mut self,
- a: ty::Region<'tcx>,
- _: ty::Region<'tcx>,
- ) -> RelateResult<'tcx, ty::Region<'tcx>> {
- debug!("TypeGeneralizer::regions(a={:?})", a);
-
- if let ty::ReLateBound(debruijn, _) = *a && debruijn < self.first_free_index {
- return Ok(a);
- }
-
- // For now, we just always create a fresh region variable to
- // replace all the regions in the source type. In the main
- // type checker, we special case the case where the ambient
- // variance is `Invariant` and try to avoid creating a fresh
- // region variable, but since this comes up so much less in
- // NLL (only when users use `_` etc) it is much less
- // important.
- //
- // As an aside, since these new variables are created in
- // `self.universe` universe, this also serves to enforce the
- // universe scoping rules.
- //
- // FIXME(#54105) -- if the ambient variance is bivariant,
- // though, we may however need to check well-formedness or
- // risk a problem like #41677 again.
-
- let replacement_region_vid = self.delegate.generalize_existential(self.universe);
-
- Ok(replacement_region_vid)
- }
-
- fn consts(
- &mut self,
- a: ty::Const<'tcx>,
- _: ty::Const<'tcx>,
- ) -> RelateResult<'tcx, ty::Const<'tcx>> {
- match a.kind() {
- ty::ConstKind::Infer(InferConst::Var(_)) if D::forbid_inference_vars() => {
- bug!("unexpected inference variable encountered in NLL generalization: {:?}", a);
- }
- ty::ConstKind::Infer(InferConst::Var(vid)) => {
- let mut inner = self.infcx.inner.borrow_mut();
- let variable_table = &mut inner.const_unification_table();
- let var_value = variable_table.probe_value(vid);
- match var_value.val.known() {
- Some(u) => self.relate(u, u),
- None => {
- let new_var_id = variable_table.new_key(ConstVarValue {
- origin: var_value.origin,
- val: ConstVariableValue::Unknown { universe: self.universe },
- });
- Ok(self.tcx().mk_const(new_var_id, a.ty()))
- }
- }
- }
- ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(a),
- _ => relate::super_relate_consts(self, a, a),
- }
- }
-
- fn binders<T>(
- &mut self,
- a: ty::Binder<'tcx, T>,
- _: ty::Binder<'tcx, T>,
- ) -> RelateResult<'tcx, ty::Binder<'tcx, T>>
- where
- T: Relate<'tcx>,
- {
- debug!("TypeGeneralizer::binders(a={:?})", a);
-
- self.first_free_index.shift_in(1);
- let result = self.relate(a.skip_binder(), a.skip_binder())?;
- self.first_free_index.shift_out(1);
- Ok(a.rebind(result))
- }
-}
diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs
index 3a0a0494a..9d5ec228d 100644
--- a/compiler/rustc_infer/src/infer/opaque_types.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types.rs
@@ -1,14 +1,14 @@
use super::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use super::{DefineOpaqueTypes, InferResult};
use crate::errors::OpaqueHiddenTypeDiag;
-use crate::infer::{DefiningAnchor, InferCtxt, InferOk};
-use crate::traits;
+use crate::infer::{InferCtxt, InferOk};
+use crate::traits::{self, PredicateObligation};
use hir::def_id::{DefId, LocalDefId};
use hir::OpaqueTyOrigin;
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::sync::Lrc;
use rustc_hir as hir;
-use rustc_middle::traits::ObligationCause;
+use rustc_middle::traits::{DefiningAnchor, ObligationCause};
use rustc_middle::ty::error::{ExpectedFound, TypeError};
use rustc_middle::ty::fold::BottomUpFolder;
use rustc_middle::ty::GenericArgKind;
@@ -48,12 +48,18 @@ impl<'tcx> InferCtxt<'tcx> {
span: Span,
param_env: ty::ParamEnv<'tcx>,
) -> InferOk<'tcx, T> {
+ // We handle opaque types differently in the new solver.
+ if self.tcx.trait_solver_next() {
+ return InferOk { value, obligations: vec![] };
+ }
+
if !value.has_opaque_types() {
return InferOk { value, obligations: vec![] };
}
+
let mut obligations = vec![];
let replace_opaque_type = |def_id: DefId| {
- def_id.as_local().map_or(false, |def_id| self.opaque_type_origin(def_id).is_some())
+ def_id.as_local().is_some_and(|def_id| self.opaque_type_origin(def_id).is_some())
};
let value = value.fold_with(&mut BottomUpFolder {
tcx: self.tcx,
@@ -149,7 +155,7 @@ impl<'tcx> InferCtxt<'tcx> {
// no one encounters it in practice.
// It does occur however in `fn fut() -> impl Future<Output = i32> { async { 42 } }`,
// where it is of no concern, so we only check for TAITs.
- if let Some(OpaqueTyOrigin::TyAlias) =
+ if let Some(OpaqueTyOrigin::TyAlias { .. }) =
b_def_id.as_local().and_then(|b_def_id| self.opaque_type_origin(b_def_id))
{
self.tcx.sess.emit_err(OpaqueHiddenTypeDiag {
@@ -381,8 +387,12 @@ impl<'tcx> InferCtxt<'tcx> {
// Anonymous `impl Trait`
hir::OpaqueTyOrigin::FnReturn(parent) => parent == parent_def_id,
// Named `type Foo = impl Bar;`
- hir::OpaqueTyOrigin::TyAlias => {
- may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
+ hir::OpaqueTyOrigin::TyAlias { in_assoc_ty } => {
+ if in_assoc_ty {
+ self.tcx.opaque_types_defined_by(parent_def_id).contains(&def_id)
+ } else {
+ may_define_opaque_type(self.tcx, parent_def_id, opaque_hir_id)
+ }
}
};
in_definition_scope.then_some(origin)
@@ -392,12 +402,7 @@ impl<'tcx> InferCtxt<'tcx> {
/// defining scope.
#[instrument(skip(self), level = "trace", ret)]
fn opaque_type_origin_unchecked(&self, def_id: LocalDefId) -> OpaqueTyOrigin {
- match self.tcx.hir().expect_item(def_id).kind {
- hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => origin,
- ref itemkind => {
- bug!("weird opaque type: {:?}, {:#?}", def_id, itemkind)
- }
- }
+ self.tcx.hir().expect_item(def_id).expect_opaque_ty().origin
}
}
@@ -522,30 +527,69 @@ impl<'tcx> InferCtxt<'tcx> {
origin: hir::OpaqueTyOrigin,
a_is_expected: bool,
) -> InferResult<'tcx, ()> {
- let tcx = self.tcx;
- let OpaqueTypeKey { def_id, substs } = opaque_type_key;
-
// Ideally, we'd get the span where *this specific `ty` came
// from*, but right now we just use the span from the overall
// value being folded. In simple cases like `-> impl Foo`,
// these are the same span, but not in cases like `-> (impl
// Foo, impl Bar)`.
let span = cause.span;
-
- let mut obligations = vec![];
let prev = self.inner.borrow_mut().opaque_types().register(
- OpaqueTypeKey { def_id, substs },
+ opaque_type_key,
OpaqueHiddenType { ty: hidden_ty, span },
origin,
);
- if let Some(prev) = prev {
- obligations = self
- .at(&cause, param_env)
+ let mut obligations = if let Some(prev) = prev {
+ self.at(&cause, param_env)
.eq_exp(DefineOpaqueTypes::Yes, a_is_expected, prev, hidden_ty)?
- .obligations;
- }
+ .obligations
+ } else {
+ Vec::new()
+ };
+
+ self.add_item_bounds_for_hidden_type(
+ opaque_type_key,
+ cause,
+ param_env,
+ hidden_ty,
+ &mut obligations,
+ );
+
+ Ok(InferOk { value: (), obligations })
+ }
- let item_bounds = tcx.bound_explicit_item_bounds(def_id.to_def_id());
+ /// Registers an opaque's hidden type -- only should be used when the opaque
+ /// can be defined. For something more fallible -- checks the anchors, tries
+ /// to unify opaques in both dirs, etc. -- use `InferCtxt::handle_opaque_type`.
+ pub fn register_hidden_type_in_new_solver(
+ &self,
+ opaque_type_key: OpaqueTypeKey<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ hidden_ty: Ty<'tcx>,
+ ) -> InferResult<'tcx, ()> {
+ assert!(self.tcx.trait_solver_next());
+ let origin = self
+ .opaque_type_origin(opaque_type_key.def_id)
+ .expect("should be called for defining usages only");
+ self.register_hidden_type(
+ opaque_type_key,
+ ObligationCause::dummy(),
+ param_env,
+ hidden_ty,
+ origin,
+ true,
+ )
+ }
+
+ pub fn add_item_bounds_for_hidden_type(
+ &self,
+ OpaqueTypeKey { def_id, substs }: OpaqueTypeKey<'tcx>,
+ cause: ObligationCause<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ hidden_ty: Ty<'tcx>,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+ ) {
+ let tcx = self.tcx;
+ let item_bounds = tcx.explicit_item_bounds(def_id);
for (predicate, _) in item_bounds.subst_iter_copied(tcx, substs) {
let predicate = predicate.fold_with(&mut BottomUpFolder {
@@ -554,16 +598,18 @@ impl<'tcx> InferCtxt<'tcx> {
// We can't normalize associated types from `rustc_infer`,
// but we can eagerly register inference variables for them.
// FIXME(RPITIT): Don't replace RPITITs with inference vars.
+ // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
ty::Alias(ty::Projection, projection_ty)
if !projection_ty.has_escaping_bound_vars()
- && !tcx.is_impl_trait_in_trait(projection_ty.def_id) =>
+ && !tcx.is_impl_trait_in_trait(projection_ty.def_id)
+ && !tcx.trait_solver_next() =>
{
self.infer_projection(
param_env,
projection_ty,
cause.clone(),
0,
- &mut obligations,
+ obligations,
)
}
// Replace all other mentions of the same opaque type with the hidden type,
@@ -574,6 +620,7 @@ impl<'tcx> InferCtxt<'tcx> {
hidden_ty
}
// FIXME(RPITIT): This can go away when we move to associated types
+ // FIXME(inherent_associated_types): Extend this to support `ty::Inherent`, too.
ty::Alias(
ty::Projection,
ty::AliasTy { def_id: def_id2, substs: substs2, .. },
@@ -588,10 +635,10 @@ impl<'tcx> InferCtxt<'tcx> {
predicate.kind().skip_binder()
{
if projection.term.references_error() {
- // No point on adding these obligations since there's a type error involved.
- return Ok(InferOk { value: (), obligations: vec![] });
+ // No point on adding any obligations since there's a type error involved.
+ obligations.clear();
+ return;
}
- trace!("{:#?}", projection.term);
}
// Require that the predicate holds for the concrete type.
debug!(?predicate);
@@ -602,7 +649,6 @@ impl<'tcx> InferCtxt<'tcx> {
predicate,
));
}
- Ok(InferOk { value: (), obligations })
}
}
diff --git a/compiler/rustc_infer/src/infer/opaque_types/table.rs b/compiler/rustc_infer/src/infer/opaque_types/table.rs
index ae4b85c87..a0f6d7eca 100644
--- a/compiler/rustc_infer/src/infer/opaque_types/table.rs
+++ b/compiler/rustc_infer/src/infer/opaque_types/table.rs
@@ -42,7 +42,7 @@ impl<'tcx> Drop for OpaqueTypeStorage<'tcx> {
fn drop(&mut self) {
if !self.opaque_types.is_empty() {
ty::tls::with(|tcx| {
- tcx.sess.delay_span_bug(DUMMY_SP, &format!("{:?}", self.opaque_types))
+ tcx.sess.delay_span_bug(DUMMY_SP, format!("{:?}", self.opaque_types))
});
}
}
diff --git a/compiler/rustc_infer/src/infer/outlives/components.rs b/compiler/rustc_infer/src/infer/outlives/components.rs
index ff23087fe..cb63d2f18 100644
--- a/compiler/rustc_infer/src/infer/outlives/components.rs
+++ b/compiler/rustc_infer/src/infer/outlives/components.rs
@@ -143,7 +143,7 @@ fn compute_components<'tcx>(
// through and constrain Pi.
let mut subcomponents = smallvec![];
let mut subvisited = SsoHashSet::new();
- compute_components_recursive(tcx, ty.into(), &mut subcomponents, &mut subvisited);
+ compute_alias_components_recursive(tcx, ty, &mut subcomponents, &mut subvisited);
out.push(Component::EscapingAlias(subcomponents.into_iter().collect()));
}
}
@@ -193,7 +193,43 @@ fn compute_components<'tcx>(
///
/// This should not be used to get the components of `parent` itself.
/// Use [push_outlives_components] instead.
-pub(super) fn compute_components_recursive<'tcx>(
+pub(super) fn compute_alias_components_recursive<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ alias_ty: Ty<'tcx>,
+ out: &mut SmallVec<[Component<'tcx>; 4]>,
+ visited: &mut SsoHashSet<GenericArg<'tcx>>,
+) {
+ let ty::Alias(kind, alias_ty) = alias_ty.kind() else { bug!() };
+ let opt_variances = if *kind == ty::Opaque { tcx.variances_of(alias_ty.def_id) } else { &[] };
+ for (index, child) in alias_ty.substs.iter().enumerate() {
+ if opt_variances.get(index) == Some(&ty::Bivariant) {
+ continue;
+ }
+ if !visited.insert(child) {
+ continue;
+ }
+ match child.unpack() {
+ GenericArgKind::Type(ty) => {
+ compute_components(tcx, ty, out, visited);
+ }
+ GenericArgKind::Lifetime(lt) => {
+ // Ignore late-bound regions.
+ if !lt.is_late_bound() {
+ out.push(Component::Region(lt));
+ }
+ }
+ GenericArgKind::Const(_) => {
+ compute_components_recursive(tcx, child, out, visited);
+ }
+ }
+ }
+}
+
+/// Collect [Component]s for *all* the substs of `parent`.
+///
+/// This should not be used to get the components of `parent` itself.
+/// Use [push_outlives_components] instead.
+fn compute_components_recursive<'tcx>(
tcx: TyCtxt<'tcx>,
parent: GenericArg<'tcx>,
out: &mut SmallVec<[Component<'tcx>; 4]>,
diff --git a/compiler/rustc_infer/src/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs
index 9a9a1696b..8a44d5031 100644
--- a/compiler/rustc_infer/src/infer/outlives/mod.rs
+++ b/compiler/rustc_infer/src/infer/outlives/mod.rs
@@ -61,7 +61,7 @@ impl<'tcx> InferCtxt<'tcx> {
};
let lexical_region_resolutions = LexicalRegionResolutions {
- values: rustc_index::vec::IndexVec::from_elem_n(
+ values: rustc_index::IndexVec::from_elem_n(
crate::infer::lexical_region_resolve::VarValue::Value(self.tcx.lifetimes.re_erased),
var_infos.len(),
),
diff --git a/compiler/rustc_infer/src/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs
index ccf11c61b..9c20c814b 100644
--- a/compiler/rustc_infer/src/infer/outlives/obligations.rs
+++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs
@@ -256,7 +256,7 @@ where
// this point it never will be
self.tcx.sess.delay_span_bug(
origin.span(),
- &format!("unresolved inference variable in outlives: {:?}", v),
+ format!("unresolved inference variable in outlives: {:?}", v),
);
}
}
@@ -344,12 +344,14 @@ where
// the problem is to add `T: 'r`, which isn't true. So, if there are no
// inference variables, we use a verify constraint instead of adding
// edges, which winds up enforcing the same condition.
+ let is_opaque = alias_ty.kind(self.tcx) == ty::Opaque;
if approx_env_bounds.is_empty()
&& trait_bounds.is_empty()
- && (alias_ty.needs_infer() || alias_ty.kind(self.tcx) == ty::Opaque)
+ && (alias_ty.has_infer() || is_opaque)
{
debug!("no declared bounds");
- self.substs_must_outlive(alias_ty.substs, origin, region);
+ let opt_variances = is_opaque.then(|| self.tcx.variances_of(alias_ty.def_id));
+ self.substs_must_outlive(alias_ty.substs, origin, region, opt_variances);
return;
}
@@ -395,22 +397,31 @@ where
self.delegate.push_verify(origin, GenericKind::Alias(alias_ty), region, verify_bound);
}
+ #[instrument(level = "debug", skip(self))]
fn substs_must_outlive(
&mut self,
substs: SubstsRef<'tcx>,
origin: infer::SubregionOrigin<'tcx>,
region: ty::Region<'tcx>,
+ opt_variances: Option<&[ty::Variance]>,
) {
let constraint = origin.to_constraint_category();
- for k in substs {
+ for (index, k) in substs.iter().enumerate() {
match k.unpack() {
GenericArgKind::Lifetime(lt) => {
- self.delegate.push_sub_region_constraint(
- origin.clone(),
- region,
- lt,
- constraint,
- );
+ let variance = if let Some(variances) = opt_variances {
+ variances[index]
+ } else {
+ ty::Invariant
+ };
+ if variance == ty::Invariant {
+ self.delegate.push_sub_region_constraint(
+ origin.clone(),
+ region,
+ lt,
+ constraint,
+ );
+ }
}
GenericArgKind::Type(ty) => {
self.type_must_outlive(origin.clone(), ty, region, constraint);
diff --git a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
index 01f900f05..cd2462d3c 100644
--- a/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
+++ b/compiler/rustc_infer/src/infer/outlives/test_type_match.rs
@@ -13,9 +13,11 @@ use crate::infer::region_constraints::VerifyIfEq;
/// Given a "verify-if-eq" type test like:
///
-/// exists<'a...> {
-/// verify_if_eq(some_type, bound_region)
-/// }
+/// ```rust,ignore (pseudo-Rust)
+/// exists<'a...> {
+/// verify_if_eq(some_type, bound_region)
+/// }
+/// ```
///
/// and the type `test_ty` that the type test is being tested against,
/// returns:
@@ -185,7 +187,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
} else if pattern == value {
Ok(pattern)
} else {
- relate::super_relate_tys(self, pattern, value)
+ relate::structurally_relate_tys(self, pattern, value)
}
}
@@ -199,7 +201,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
if pattern == value {
Ok(pattern)
} else {
- relate::super_relate_consts(self, pattern, value)
+ relate::structurally_relate_consts(self, pattern, value)
}
}
diff --git a/compiler/rustc_infer/src/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs
index bae246418..c2bf0f3db 100644
--- a/compiler/rustc_infer/src/infer/outlives/verify.rs
+++ b/compiler/rustc_infer/src/infer/outlives/verify.rs
@@ -1,4 +1,4 @@
-use crate::infer::outlives::components::{compute_components_recursive, Component};
+use crate::infer::outlives::components::{compute_alias_components_recursive, Component};
use crate::infer::outlives::env::RegionBoundPairs;
use crate::infer::region_constraints::VerifyIfEq;
use crate::infer::VerifyBound;
@@ -130,7 +130,12 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// see the extensive comment in projection_must_outlive
let recursive_bound = {
let mut components = smallvec![];
- compute_components_recursive(self.tcx, alias_ty_as_ty.into(), &mut components, visited);
+ compute_alias_components_recursive(
+ self.tcx,
+ alias_ty_as_ty.into(),
+ &mut components,
+ visited,
+ );
self.bound_from_components(&components, visited)
};
@@ -174,7 +179,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
// this point it never will be
self.tcx.sess.delay_span_bug(
rustc_span::DUMMY_SP,
- &format!("unresolved inference variable in outlives: {:?}", v),
+ format!("unresolved inference variable in outlives: {:?}", v),
);
// add a bound that never holds
VerifyBound::AnyBound(vec![])
@@ -272,7 +277,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> {
///
/// It will not, however, work for higher-ranked bounds like:
///
- /// ```compile_fail,E0311
+ /// ```ignore(this does compile today, previously was marked as `compile_fail,E0311`)
/// trait Foo<'a, 'b>
/// where for<'x> <Self as Foo<'x, 'b>>::Bar: 'x
/// {
diff --git a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
index b8ba98fc0..89cfc9ea3 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::{
graph::{scc::Sccs, vec_graph::VecGraph},
undo_log::UndoLogs,
};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::relate::RelateResult;
diff --git a/compiler/rustc_infer/src/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
index 7b272dfd2..c7a307b89 100644
--- a/compiler/rustc_infer/src/infer/region_constraints/mod.rs
+++ b/compiler/rustc_infer/src/infer/region_constraints/mod.rs
@@ -12,7 +12,7 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::sync::Lrc;
use rustc_data_structures::undo_log::UndoLogs;
use rustc_data_structures::unify as ut;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::infer::unify_key::{RegionVidKey, UnifiedRegion};
use rustc_middle::ty::ReStatic;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -217,7 +217,7 @@ pub enum VerifyBound<'tcx> {
/// and supplies a bound if it ended up being relevant. It's used in situations
/// like this:
///
-/// ```rust
+/// ```rust,ignore (pseudo-Rust)
/// fn foo<'a, 'b, T: SomeTrait<'a>>
/// where
/// <T as SomeTrait<'a>>::Item: 'b
@@ -232,7 +232,7 @@ pub enum VerifyBound<'tcx> {
/// In the [`VerifyBound`], this struct is enclosed in `Binder` to account
/// for cases like
///
-/// ```rust
+/// ```rust,ignore (pseudo-Rust)
/// where for<'a> <T as SomeTrait<'a>::Item: 'a
/// ```
///
diff --git a/compiler/rustc_infer/src/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs
index 4f49f4165..3c41e8b37 100644
--- a/compiler/rustc_infer/src/infer/resolve.rs
+++ b/compiler/rustc_infer/src/infer/resolve.rs
@@ -213,7 +213,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
}
fn try_fold_ty(&mut self, t: Ty<'tcx>) -> Result<Ty<'tcx>, Self::Error> {
- if !t.needs_infer() {
+ if !t.has_infer() {
Ok(t) // micro-optimize -- if there is nothing in this type that this fold affects...
} else {
let t = self.infcx.shallow_resolve(t);
@@ -243,7 +243,7 @@ impl<'a, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for FullTypeResolver<'a, 'tcx> {
}
fn try_fold_const(&mut self, c: ty::Const<'tcx>) -> Result<ty::Const<'tcx>, Self::Error> {
- if !c.needs_infer() {
+ if !c.has_infer() {
Ok(c) // micro-optimize -- if there is nothing in this const that this fold affects...
} else {
let c = self.infcx.shallow_resolve(c);
diff --git a/compiler/rustc_infer/src/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs
index 0dd73a6e9..ceafafb55 100644
--- a/compiler/rustc_infer/src/infer/sub.rs
+++ b/compiler/rustc_infer/src/infer/sub.rs
@@ -1,4 +1,4 @@
-use super::combine::{CombineFields, RelationDir};
+use super::combine::CombineFields;
use super::{DefineOpaqueTypes, ObligationEmittingRelation, SubregionOrigin};
use crate::traits::{Obligation, PredicateObligations};
@@ -108,11 +108,11 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
Ok(a)
}
(&ty::Infer(TyVar(a_id)), _) => {
- self.fields.instantiate(b, RelationDir::SupertypeOf, a_id, !self.a_is_expected)?;
+ self.fields.instantiate(b, ty::Contravariant, a_id, !self.a_is_expected)?;
Ok(a)
}
(_, &ty::Infer(TyVar(b_id))) => {
- self.fields.instantiate(a, RelationDir::SubtypeOf, b_id, self.a_is_expected)?;
+ self.fields.instantiate(a, ty::Covariant, b_id, self.a_is_expected)?;
Ok(a)
}
@@ -131,7 +131,8 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
(&ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }), _)
| (_, &ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }))
if self.fields.define_opaque_types == DefineOpaqueTypes::Yes
- && def_id.is_local() =>
+ && def_id.is_local()
+ && !self.tcx().trait_solver_next() =>
{
self.fields.obligations.extend(
infcx
@@ -210,7 +211,7 @@ impl<'tcx> TypeRelation<'tcx> for Sub<'_, '_, 'tcx> {
where
T: Relate<'tcx>,
{
- // A binder is always a subtype of itself if it's structually equal to itself
+ // A binder is always a subtype of itself if it's structurally equal to itself
if a == b {
return Ok(a);
}
diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs
index 738a12376..e92ba05aa 100644
--- a/compiler/rustc_infer/src/lib.rs
+++ b/compiler/rustc_infer/src/lib.rs
@@ -35,7 +35,7 @@ extern crate tracing;
extern crate rustc_middle;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
mod errors;
pub mod infer;
diff --git a/compiler/rustc_infer/src/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs
index b8940e2f0..11f434694 100644
--- a/compiler/rustc_infer/src/traits/engine.rs
+++ b/compiler/rustc_infer/src/traits/engine.rs
@@ -18,7 +18,7 @@ pub trait TraitEngine<'tcx>: 'tcx {
def_id: DefId,
cause: ObligationCause<'tcx>,
) {
- let trait_ref = infcx.tcx.mk_trait_ref(def_id, [ty]);
+ let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
self.register_predicate_obligation(
infcx,
Obligation {
diff --git a/compiler/rustc_infer/src/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
index 4d5351958..b5a7d0326 100644
--- a/compiler/rustc_infer/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_infer/src/traits/error_reporting/mod.rs
@@ -73,7 +73,7 @@ pub fn report_object_safety_error<'tcx>(
format!("...because {}", violation.error_msg())
};
if spans.is_empty() {
- err.note(&msg);
+ err.note(msg);
} else {
for span in spans {
multi_span.push(span);
diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs
index e01b6caf4..8ce8b4e20 100644
--- a/compiler/rustc_infer/src/traits/mod.rs
+++ b/compiler/rustc_infer/src/traits/mod.rs
@@ -89,10 +89,10 @@ impl<'tcx> PredicateObligation<'tcx> {
impl<'tcx> TraitObligation<'tcx> {
/// Returns `true` if the trait predicate is considered `const` in its ParamEnv.
pub fn is_const(&self) -> bool {
- match (self.predicate.skip_binder().constness, self.param_env.constness()) {
- (ty::BoundConstness::ConstIfConst, hir::Constness::Const) => true,
- _ => false,
- }
+ matches!(
+ (self.predicate.skip_binder().constness, self.param_env.constness()),
+ (ty::BoundConstness::ConstIfConst, hir::Constness::Const)
+ )
}
pub fn derived_cause(
@@ -123,7 +123,7 @@ pub struct FulfillmentError<'tcx> {
#[derive(Clone)]
pub enum FulfillmentErrorCode<'tcx> {
/// Inherently impossible to fulfill; this trait is implemented if and only if it is already implemented.
- CodeCycle(Vec<Obligation<'tcx, ty::Predicate<'tcx>>>),
+ CodeCycle(Vec<PredicateObligation<'tcx>>),
CodeSelectionError(SelectionError<'tcx>),
CodeProjectionError(MismatchedProjectionTypes<'tcx>),
CodeSubtypeError(ExpectedFound<Ty<'tcx>>, TypeError<'tcx>), // always comes from a SubtypePredicate
diff --git a/compiler/rustc_infer/src/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs
index ac455055b..e375d6119 100644
--- a/compiler/rustc_infer/src/traits/project.rs
+++ b/compiler/rustc_infer/src/traits/project.rs
@@ -20,7 +20,7 @@ pub struct MismatchedProjectionTypes<'tcx> {
pub err: ty::error::TypeError<'tcx>,
}
-#[derive(Clone, TypeFoldable, TypeVisitable)]
+#[derive(Clone)]
pub struct Normalized<'tcx, T> {
pub value: T,
pub obligations: Vec<PredicateObligation<'tcx>>,
@@ -103,7 +103,7 @@ pub enum ProjectionCacheEntry<'tcx> {
/// if this field is set. Evaluation only
/// cares about the final result, so we don't
/// care about any region constraint side-effects
- /// produced by evaluating the sub-boligations.
+ /// produced by evaluating the sub-obligations.
///
/// Additionally, we will clear out the sub-obligations
/// entirely if we ever evaluate the cache entry (along
diff --git a/compiler/rustc_infer/src/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs
index ef01d5d51..74a78f380 100644
--- a/compiler/rustc_infer/src/traits/util.rs
+++ b/compiler/rustc_infer/src/traits/util.rs
@@ -200,6 +200,10 @@ impl<'tcx, O: Elaboratable<'tcx>> Elaborator<'tcx, O> {
let bound_predicate = elaboratable.predicate().kind();
match bound_predicate.skip_binder() {
ty::PredicateKind::Clause(ty::Clause::Trait(data)) => {
+ // Negative trait bounds do not imply any supertrait bounds
+ if data.polarity == ty::ImplPolarity::Negative {
+ return;
+ }
// Get predicates implied by the trait, or only super predicates if we only care about self predicates.
let predicates = if self.only_self {
tcx.super_predicates_of(data.def_id())
@@ -376,11 +380,11 @@ pub fn transitive_bounds<'tcx>(
}
/// A specialized variant of `elaborate` that only elaborates trait references that may
-/// define the given associated type `assoc_name`. It uses the
-/// `super_predicates_that_define_assoc_type` query to avoid enumerating super-predicates that
+/// define the given associated item with the name `assoc_name`. It uses the
+/// `super_predicates_that_define_assoc_item` query to avoid enumerating super-predicates that
/// aren't related to `assoc_item`. This is used when resolving types like `Self::Item` or
/// `T::Item` and helps to avoid cycle errors (see e.g. #35237).
-pub fn transitive_bounds_that_define_assoc_type<'tcx>(
+pub fn transitive_bounds_that_define_assoc_item<'tcx>(
tcx: TyCtxt<'tcx>,
bounds: impl Iterator<Item = ty::PolyTraitRef<'tcx>>,
assoc_name: Ident,
@@ -393,7 +397,7 @@ pub fn transitive_bounds_that_define_assoc_type<'tcx>(
let anon_trait_ref = tcx.anonymize_bound_vars(trait_ref);
if visited.insert(anon_trait_ref) {
let super_predicates =
- tcx.super_predicates_that_define_assoc_type((trait_ref.def_id(), assoc_name));
+ tcx.super_predicates_that_define_assoc_item((trait_ref.def_id(), assoc_name));
for (super_predicate, _) in super_predicates.predicates {
let subst_predicate = super_predicate.subst_supertrait(tcx, &trait_ref);
if let Some(binder) = subst_predicate.to_opt_poly_trait_pred() {
diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml
index 98d3ab87f..2c7438ed9 100644
--- a/compiler/rustc_interface/Cargo.toml
+++ b/compiler/rustc_interface/Cargo.toml
@@ -10,12 +10,12 @@ libloading = "0.7.1"
tracing = "0.1"
rustc-rayon-core = { version = "0.5.0", optional = true }
rustc-rayon = { version = "0.5.0", optional = true }
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
rustc_ast = { path = "../rustc_ast" }
rustc_attr = { path = "../rustc_attr" }
rustc_borrowck = { path = "../rustc_borrowck" }
rustc_builtin_macros = { path = "../rustc_builtin_macros" }
rustc_expand = { path = "../rustc_expand" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_macros = { path = "../rustc_macros" }
rustc_parse = { path = "../rustc_parse" }
@@ -44,6 +44,7 @@ rustc_lint = { path = "../rustc_lint" }
rustc_errors = { path = "../rustc_errors" }
rustc_plugin_impl = { path = "../rustc_plugin_impl" }
rustc_privacy = { path = "../rustc_privacy" }
+rustc_query_system = { path = "../rustc_query_system" }
rustc_query_impl = { path = "../rustc_query_impl" }
rustc_resolve = { path = "../rustc_resolve" }
rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_interface/messages.ftl b/compiler/rustc_interface/messages.ftl
index 37994899a..be1a75f02 100644
--- a/compiler/rustc_interface/messages.ftl
+++ b/compiler/rustc_interface/messages.ftl
@@ -1,33 +1,43 @@
-interface_ferris_identifier =
- Ferris cannot be used as an identifier
- .suggestion = try using their name instead
+interface_cant_emit_mir =
+ could not emit MIR: {$error}
interface_emoji_identifier =
identifiers cannot contain emoji: `{$ident}`
-interface_mixed_bin_crate =
- cannot mix `bin` crate type with others
-
-interface_mixed_proc_macro_crate =
- cannot mix `proc-macro` crate type with others
-
interface_error_writing_dependencies =
error writing dependencies to `{$path}`: {$error}
-interface_input_file_would_be_overwritten =
- the input file "{$path}" would be overwritten by the generated executable
+interface_failed_writing_file =
+ failed to write file {$path}: {$error}"
+
+interface_ferris_identifier =
+ Ferris cannot be used as an identifier
+ .suggestion = try using their name instead
interface_generated_file_conflicts_with_directory =
the generated executable for the input file "{$input_path}" conflicts with the existing directory "{$dir_path}"
-interface_temps_dir_error =
- failed to find or create the directory specified by `--temps-dir`
+interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag
+
+interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
+
+interface_input_file_would_be_overwritten =
+ the input file "{$path}" would be overwritten by the generated executable
+
+interface_mixed_bin_crate =
+ cannot mix `bin` crate type with others
+
+interface_mixed_proc_macro_crate =
+ cannot mix `proc-macro` crate type with others
+
+interface_multiple_output_types_adaption =
+ due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
interface_out_dir_error =
failed to find or create the directory specified by `--out-dir`
-interface_cant_emit_mir =
- could not emit MIR: {$error}
+interface_proc_macro_crate_panic_abort =
+ building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
interface_rustc_error_fatal =
fatal error triggered by #[rustc_error]
@@ -35,18 +45,8 @@ interface_rustc_error_fatal =
interface_rustc_error_unexpected_annotation =
unexpected annotation used with `#[rustc_error(...)]`!
-interface_failed_writing_file =
- failed to write file {$path}: {$error}"
-
-interface_proc_macro_crate_panic_abort =
- building proc macro crate with `panic=abort` may crash the compiler should the proc-macro panic
+interface_temps_dir_error =
+ failed to find or create the directory specified by `--temps-dir`
interface_unsupported_crate_type_for_target =
dropping unsupported crate type `{$crate_type}` for target `{$target_triple}`
-
-interface_multiple_output_types_adaption =
- due to multiple output types requested, the explicitly specified output file name will be adapted for each output type
-
-interface_ignoring_extra_filename = ignoring -C extra-filename flag due to -o flag
-
-interface_ignoring_out_dir = ignoring --out-dir flag due to -o flag
diff --git a/compiler/rustc_interface/src/interface.rs b/compiler/rustc_interface/src/interface.rs
index be7fa9378..39d568979 100644
--- a/compiler/rustc_interface/src/interface.rs
+++ b/compiler/rustc_interface/src/interface.rs
@@ -3,16 +3,19 @@ use crate::util;
use rustc_ast::token;
use rustc_ast::{self as ast, LitKind, MetaItemKind};
use rustc_codegen_ssa::traits::CodegenBackend;
+use rustc_data_structures::defer;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::OnDrop;
use rustc_errors::registry::Registry;
use rustc_errors::{ErrorGuaranteed, Handler};
use rustc_lint::LintStore;
-use rustc_middle::ty;
+use rustc_middle::query::{ExternProviders, Providers};
+use rustc_middle::{bug, ty};
use rustc_parse::maybe_new_parser_from_source_str;
use rustc_query_impl::QueryCtxt;
-use rustc_session::config::{self, CheckCfg, ErrorOutputType, Input, OutputFilenames};
+use rustc_query_system::query::print_query_stack;
+use rustc_session::config::{self, ErrorOutputType, Input, OutputFilenames};
+use rustc_session::config::{CheckCfg, ExpectedValues};
use rustc_session::lint;
use rustc_session::parse::{CrateConfig, ParseSess};
use rustc_session::Session;
@@ -35,8 +38,7 @@ pub struct Compiler {
pub(crate) sess: Lrc<Session>,
codegen_backend: Lrc<Box<dyn CodegenBackend>>,
pub(crate) register_lints: Option<Box<dyn Fn(&Session, &mut LintStore) + Send + Sync>>,
- pub(crate) override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
+ pub(crate) override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>,
}
impl Compiler {
@@ -58,6 +60,11 @@ impl Compiler {
}
}
+#[allow(rustc::bad_opt_access)]
+pub fn set_thread_safe_mode(sopts: &config::UnstableOptions) {
+ rustc_data_structures::sync::set_dyn_thread_safe_mode(sopts.threads > 1);
+}
+
/// Converts strings provided as `--cfg [cfgspec]` into a `crate_cfg`.
pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String>)> {
rustc_span::create_default_session_if_not_set_then(move |_| {
@@ -73,7 +80,7 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
($reason: expr) => {
early_error(
ErrorOutputType::default(),
- &format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
+ format!(concat!("invalid `--cfg` argument: `{}` (", $reason, ")"), s),
);
};
}
@@ -120,9 +127,9 @@ pub fn parse_cfgspecs(cfgspecs: Vec<String>) -> FxHashSet<(String, Option<String
/// Converts strings provided as `--check-cfg [specs]` into a `CheckCfg`.
pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
rustc_span::create_default_session_if_not_set_then(move |_| {
- let mut cfg = CheckCfg::default();
+ let mut check_cfg = CheckCfg::default();
- 'specs: for s in specs {
+ for s in specs {
let sess = ParseSess::with_silent_emitter(Some(format!(
"this error occurred on the command line: `--check-cfg={s}`"
)));
@@ -132,44 +139,64 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
($reason: expr) => {
early_error(
ErrorOutputType::default(),
- &format!(
- concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"),
- s
- ),
- );
+ format!(concat!("invalid `--check-cfg` argument: `{}` (", $reason, ")"), s),
+ )
};
}
+ let expected_error = || {
+ error!(
+ "expected `names(name1, name2, ... nameN)` or \
+ `values(name, \"value1\", \"value2\", ... \"valueN\")`"
+ )
+ };
+
match maybe_new_parser_from_source_str(&sess, filename, s.to_string()) {
Ok(mut parser) => match parser.parse_meta_item() {
Ok(meta_item) if parser.token == token::Eof => {
if let Some(args) = meta_item.meta_item_list() {
if meta_item.has_name(sym::names) {
- let names_valid =
- cfg.names_valid.get_or_insert_with(|| FxHashSet::default());
+ check_cfg.exhaustive_names = true;
for arg in args {
if arg.is_word() && arg.ident().is_some() {
let ident = arg.ident().expect("multi-segment cfg key");
- names_valid.insert(ident.name.to_string());
+ check_cfg
+ .expecteds
+ .entry(ident.name.to_string())
+ .or_insert(ExpectedValues::Any);
} else {
error!("`names()` arguments must be simple identifiers");
}
}
- continue 'specs;
} else if meta_item.has_name(sym::values) {
if let Some((name, values)) = args.split_first() {
if name.is_word() && name.ident().is_some() {
let ident = name.ident().expect("multi-segment cfg key");
- let ident_values = cfg
- .values_valid
+ let expected_values = check_cfg
+ .expecteds
.entry(ident.name.to_string())
- .or_insert_with(|| FxHashSet::default());
+ .and_modify(|expected_values| match expected_values {
+ ExpectedValues::Some(_) => {}
+ ExpectedValues::Any => {
+ // handle the case where names(...) was done
+ // before values by changing to a list
+ *expected_values =
+ ExpectedValues::Some(FxHashSet::default());
+ }
+ })
+ .or_insert_with(|| {
+ ExpectedValues::Some(FxHashSet::default())
+ });
+
+ let ExpectedValues::Some(expected_values) = expected_values else {
+ bug!("`expected_values` should be a list a values")
+ };
for val in values {
if let Some(LitKind::Str(s, _)) =
val.lit().map(|lit| &lit.kind)
{
- ident_values.insert(s.to_string());
+ expected_values.insert(Some(s.to_string()));
} else {
error!(
"`values()` arguments must be string literals"
@@ -177,35 +204,40 @@ pub fn parse_check_cfg(specs: Vec<String>) -> CheckCfg {
}
}
- continue 'specs;
+ if values.is_empty() {
+ expected_values.insert(None);
+ }
} else {
error!(
"`values()` first argument must be a simple identifier"
);
}
} else if args.is_empty() {
- cfg.well_known_values = true;
- continue 'specs;
+ check_cfg.exhaustive_values = true;
+ } else {
+ expected_error();
}
+ } else {
+ expected_error();
}
+ } else {
+ expected_error();
}
}
- Ok(..) => {}
- Err(err) => err.cancel(),
+ Ok(..) => expected_error(),
+ Err(err) => {
+ err.cancel();
+ expected_error();
+ }
},
- Err(errs) => drop(errs),
+ Err(errs) => {
+ drop(errs);
+ expected_error();
+ }
}
-
- error!(
- "expected `names(name1, name2, ... nameN)` or \
- `values(name, \"value1\", \"value2\", ... \"valueN\")`"
- );
}
- if let Some(names_valid) = &mut cfg.names_valid {
- names_valid.extend(cfg.values_valid.keys().cloned());
- }
- cfg
+ check_cfg
})
}
@@ -240,8 +272,7 @@ pub struct Config {
/// the list of queries.
///
/// The second parameter is local providers and the third parameter is external providers.
- pub override_queries:
- Option<fn(&Session, &mut ty::query::Providers, &mut ty::query::ExternProviders)>,
+ pub override_queries: Option<fn(&Session, &mut Providers, &mut ExternProviders)>,
/// This is a callback from the driver that is called to create a codegen backend.
pub make_codegen_backend:
@@ -294,7 +325,7 @@ pub fn run_compiler<R: Send>(config: Config, f: impl FnOnce(&Compiler) -> R + Se
rustc_span::set_source_map(compiler.sess.parse_sess.clone_source_map(), move || {
let r = {
- let _sess_abort_error = OnDrop(|| {
+ let _sess_abort_error = defer(|| {
compiler.sess.finish_diagnostics(registry);
});
@@ -317,7 +348,7 @@ pub fn try_print_query_stack(handler: &Handler, num_frames: Option<usize>) {
// state if it was responsible for triggering the panic.
let i = ty::tls::with_context_opt(|icx| {
if let Some(icx) = icx {
- QueryCtxt::from_tcx(icx.tcx).try_print_query_stack(icx.query, handler, num_frames)
+ print_query_stack(QueryCtxt::new(icx.tcx), icx.query, handler, num_frames)
} else {
0
}
diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs
index 9664ba8bd..51bd8381e 100644
--- a/compiler/rustc_interface/src/lib.rs
+++ b/compiler/rustc_interface/src/lib.rs
@@ -13,7 +13,7 @@
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
mod callbacks;
mod errors;
diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs
index 0e4e20c7c..42d8d2280 100644
--- a/compiler/rustc_interface/src/passes.rs
+++ b/compiler/rustc_interface/src/passes.rs
@@ -17,13 +17,12 @@ use rustc_lint::{unerased_lint_store, BufferedEarlyLint, EarlyCheckNode, LintSto
use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
-use rustc_middle::ty::query::{ExternProviders, Providers};
+use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, GlobalCtxt, RegisteredTools, TyCtxt};
use rustc_mir_build as mir_build;
use rustc_parse::{parse_crate_from_file, parse_crate_from_source_str, validate_attr};
use rustc_passes::{self, hir_stats, layout_test};
use rustc_plugin_impl as plugin;
-use rustc_query_impl::{OnDiskCache, Queries as TcxQueries};
use rustc_resolve::Resolver;
use rustc_session::config::{CrateType, Input, OutputFilenames, OutputType};
use rustc_session::cstore::{MetadataLoader, Untracked};
@@ -90,6 +89,7 @@ pub fn register_plugins<'a>(
crate_name,
sess.crate_types().contains(&CrateType::Executable),
sess.opts.cg.metadata.clone(),
+ sess.cfg_version,
);
sess.stable_crate_id.set(stable_crate_id).expect("not yet initialized");
rustc_incremental::prepare_session_directory(sess, crate_name, stable_crate_id)?;
@@ -487,6 +487,11 @@ fn write_out_deps(tcx: TyCtxt<'_>, outputs: &OutputFilenames, out_filenames: &[P
files.push(normalize_path(profile_sample.as_path().to_path_buf()));
}
+ // Debugger visualizer files
+ for debugger_visualizer in tcx.debugger_visualizers(LOCAL_CRATE) {
+ files.push(normalize_path(debugger_visualizer.path.clone().unwrap()));
+ }
+
if sess.binary_dep_depinfo() {
if let Some(ref backend) = sess.opts.unstable_opts.codegen_backend {
if backend.contains('.') {
@@ -669,7 +674,6 @@ pub fn create_global_ctxt<'tcx>(
lint_store: Lrc<LintStore>,
dep_graph: DepGraph,
untracked: Untracked,
- queries: &'tcx OnceCell<TcxQueries<'tcx>>,
gcx_cell: &'tcx OnceCell<GlobalCtxt<'tcx>>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<rustc_hir::Arena<'tcx>>,
@@ -693,9 +697,7 @@ pub fn create_global_ctxt<'tcx>(
callback(sess, &mut local_providers, &mut extern_providers);
}
- let queries = queries.get_or_init(|| {
- TcxQueries::new(local_providers, extern_providers, query_result_on_disk_cache)
- });
+ let incremental = dep_graph.is_fully_enabled();
sess.time("setup_global_ctxt", || {
gcx_cell.get_or_init(move || {
@@ -706,9 +708,13 @@ pub fn create_global_ctxt<'tcx>(
hir_arena,
untracked,
dep_graph,
- queries.on_disk_cache.as_ref().map(OnDiskCache::as_dyn),
- queries.as_dyn(),
rustc_query_impl::query_callbacks(arena),
+ rustc_query_impl::query_system(
+ local_providers,
+ extern_providers,
+ query_result_on_disk_cache,
+ incremental,
+ ),
)
})
})
@@ -761,27 +767,6 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
// passes are timed inside typeck
rustc_hir_analysis::check_crate(tcx)?;
- sess.time("misc_checking_2", || {
- parallel!(
- {
- sess.time("match_checking", || {
- tcx.hir().par_body_owners(|def_id| tcx.ensure().check_match(def_id))
- });
- },
- {
- sess.time("liveness_checking", || {
- tcx.hir().par_body_owners(|def_id| {
- // this must run before MIR dump, because
- // "not all control paths return a value" is reported here.
- //
- // maybe move the check to a MIR pass?
- tcx.ensure().check_liveness(def_id.to_def_id());
- });
- });
- }
- );
- });
-
sess.time("MIR_borrow_checking", || {
tcx.hir().par_body_owners(|def_id| tcx.ensure().mir_borrowck(def_id));
});
@@ -794,9 +779,14 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> {
}
tcx.ensure().has_ffi_unwind_calls(def_id);
- if tcx.hir().body_const_context(def_id).is_some() {
- tcx.ensure()
- .mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(def_id));
+ // If we need to codegen, ensure that we emit all errors from
+ // `mir_drops_elaborated_and_const_checked` now, to avoid discovering
+ // them later during codegen.
+ if tcx.sess.opts.output_types.should_codegen()
+ || tcx.hir().body_const_context(def_id).is_some()
+ {
+ tcx.ensure().mir_drops_elaborated_and_const_checked(def_id);
+ tcx.ensure().unused_generic_params(ty::InstanceDef::Item(def_id.to_def_id()));
}
}
});
diff --git a/compiler/rustc_interface/src/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs
index 1c58caa03..2c8014d8b 100644
--- a/compiler/rustc_interface/src/proc_macro_decls.rs
+++ b/compiler/rustc_interface/src/proc_macro_decls.rs
@@ -1,6 +1,6 @@
use rustc_ast::attr;
use rustc_hir::def_id::LocalDefId;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::sym;
diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs
index 818f450a5..c441a8ffd 100644
--- a/compiler/rustc_interface/src/queries.rs
+++ b/compiler/rustc_interface/src/queries.rs
@@ -16,7 +16,6 @@ use rustc_metadata::creader::CStore;
use rustc_middle::arena::Arena;
use rustc_middle::dep_graph::DepGraph;
use rustc_middle::ty::{GlobalCtxt, TyCtxt};
-use rustc_query_impl::Queries as TcxQueries;
use rustc_session::config::{self, OutputFilenames, OutputType};
use rustc_session::cstore::Untracked;
use rustc_session::{output::find_crate_name, Session};
@@ -81,7 +80,6 @@ impl<T> Default for Query<T> {
pub struct Queries<'tcx> {
compiler: &'tcx Compiler,
gcx_cell: OnceCell<GlobalCtxt<'tcx>>,
- queries: OnceCell<TcxQueries<'tcx>>,
arena: WorkerLocal<Arena<'tcx>>,
hir_arena: WorkerLocal<rustc_hir::Arena<'tcx>>,
@@ -102,7 +100,6 @@ impl<'tcx> Queries<'tcx> {
Queries {
compiler,
gcx_cell: OnceCell::new(),
- queries: OnceCell::new(),
arena: WorkerLocal::new(|_| Arena::default()),
hir_arena: WorkerLocal::new(|_| rustc_hir::Arena::default()),
dep_graph_future: Default::default(),
@@ -225,7 +222,6 @@ impl<'tcx> Queries<'tcx> {
lint_store,
self.dep_graph()?.steal(),
untracked,
- &self.queries,
&self.gcx_cell,
&self.arena,
&self.hir_arena,
@@ -372,9 +368,8 @@ impl Linker {
}
if sess.opts.unstable_opts.no_link {
- let encoded = CodegenResults::serialize_rlink(&codegen_results);
let rlink_file = self.prepare_outputs.with_extension(config::RLINK_EXT);
- std::fs::write(&rlink_file, encoded)
+ CodegenResults::serialize_rlink(sess, &rlink_file, &codegen_results)
.map_err(|error| sess.emit_fatal(FailedWritingFile { path: &rlink_file, error }))?;
return Ok(());
}
diff --git a/compiler/rustc_interface/src/tests.rs b/compiler/rustc_interface/src/tests.rs
index 10dfd32d4..28e719a40 100644
--- a/compiler/rustc_interface/src/tests.rs
+++ b/compiler/rustc_interface/src/tests.rs
@@ -52,7 +52,8 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) {
output_file: None,
temps_dir,
};
- let sess = build_session(sessopts, io, None, registry, vec![], Default::default(), None, None);
+ let sess =
+ build_session(sessopts, io, None, registry, vec![], Default::default(), None, None, "");
(sess, cfg)
}
@@ -69,6 +70,7 @@ where
is_private_dep: false,
add_prelude: true,
nounused_dep: false,
+ force: false,
}
}
@@ -547,6 +549,7 @@ fn test_codegen_options_tracking_hash() {
untracked!(ar, String::from("abc"));
untracked!(codegen_units, Some(42));
untracked!(default_linker_libraries, true);
+ untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
untracked!(extra_filename, String::from("extra-filename"));
untracked!(incremental, Some(String::from("abc")));
// `link_arg` is omitted because it just forwards to `link_args`.
@@ -651,7 +654,6 @@ fn test_unstable_options_tracking_hash() {
untracked!(assert_incr_state, Some(String::from("loaded")));
untracked!(deduplicate_diagnostics, false);
untracked!(dep_tasks, true);
- untracked!(dlltool, Some(PathBuf::from("custom_dlltool.exe")));
untracked!(dont_buffer_diagnostics, true);
untracked!(dump_dep_graph, true);
untracked!(dump_drop_tracking_cfg, Some("cfg.dot".to_string()));
@@ -747,7 +749,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(emit_thin_lto, false);
tracked!(export_executable_symbols, true);
tracked!(fewer_names, Some(true));
- tracked!(flatten_format_args, true);
+ tracked!(flatten_format_args, false);
tracked!(force_unstable_if_unmarked, true);
tracked!(fuel, Some(("abc".to_string(), 99)));
tracked!(function_sections, Some(false));
@@ -768,6 +770,7 @@ fn test_unstable_options_tracking_hash() {
tracked!(merge_functions, Some(MergeFunctions::Disabled));
tracked!(mir_emit_retag, true);
tracked!(mir_enable_passes, vec![("DestProp".to_string(), false)]);
+ tracked!(mir_keep_place_mention, true);
tracked!(mir_opt_level, Some(4));
tracked!(move_size_limit, Some(4096));
tracked!(mutable_noalias, false);
@@ -794,12 +797,16 @@ fn test_unstable_options_tracking_hash() {
tracked!(remap_cwd_prefix, Some(PathBuf::from("abc")));
tracked!(report_delayed_bugs, true);
tracked!(sanitizer, SanitizerSet::ADDRESS);
+ tracked!(sanitizer_cfi_canonical_jump_tables, None);
+ tracked!(sanitizer_cfi_generalize_pointers, Some(true));
+ tracked!(sanitizer_cfi_normalize_integers, Some(true));
tracked!(sanitizer_memory_track_origins, 2);
tracked!(sanitizer_recover, SanitizerSet::ADDRESS);
tracked!(saturating_float_casts, Some(true));
tracked!(share_generics, Some(true));
tracked!(show_span, Some(String::from("abc")));
tracked!(simulate_remapped_rust_src_base, Some(PathBuf::from("/rustc/abc")));
+ tracked!(split_lto_unit, Some(true));
tracked!(src_hash_algorithm, Some(SourceFileHashAlgorithm::Sha1));
tracked!(stack_protector, StackProtector::All);
tracked!(symbol_mangling_version, Some(SymbolManglingVersion::V0));
diff --git a/compiler/rustc_interface/src/util.rs b/compiler/rustc_interface/src/util.rs
index 612903810..cb1975020 100644
--- a/compiler/rustc_interface/src/util.rs
+++ b/compiler/rustc_interface/src/util.rs
@@ -4,6 +4,8 @@ use libloading::Library;
use rustc_ast as ast;
use rustc_codegen_ssa::traits::CodegenBackend;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
+#[cfg(parallel_compiler)]
+use rustc_data_structures::sync;
use rustc_errors::registry::Registry;
use rustc_parse::validate_attr;
use rustc_session as session;
@@ -86,7 +88,7 @@ pub fn create_session(
) {
Ok(bundle) => bundle,
Err(e) => {
- early_error(sopts.error_format, &format!("failed to load fluent bundle: {e}"));
+ early_error(sopts.error_format, format!("failed to load fluent bundle: {e}"));
}
};
@@ -102,6 +104,7 @@ pub fn create_session(
lint_caps,
file_loader,
target_override,
+ rustc_version_str().unwrap_or("unknown"),
);
codegen_backend.init(&sess);
@@ -168,8 +171,10 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
) -> R {
use rustc_data_structures::jobserver;
use rustc_middle::ty::tls;
- use rustc_query_impl::{deadlock, QueryContext, QueryCtxt};
+ use rustc_query_impl::QueryCtxt;
+ use rustc_query_system::query::{deadlock, QueryContext};
+ let registry = sync::Registry::new(threads);
let mut builder = rayon::ThreadPoolBuilder::new()
.thread_name(|_| "rustc".to_string())
.acquire_thread_handler(jobserver::acquire_thread)
@@ -179,7 +184,7 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
// On deadlock, creates a new thread and forwards information in thread
// locals to it. The new thread runs the deadlock handler.
let query_map = tls::with(|tcx| {
- QueryCtxt::from_tcx(tcx)
+ QueryCtxt::new(tcx)
.try_collect_active_jobs()
.expect("active jobs shouldn't be locked in deadlock handler")
});
@@ -200,6 +205,9 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
.build_scoped(
// Initialize each new worker thread when created.
move |thread: rayon::ThreadBuilder| {
+ // Register the thread for use with the `WorkerLocal` type.
+ registry.register();
+
rustc_span::set_session_globals_then(session_globals, || thread.run())
},
// Run `f` on the first thread in the thread pool.
@@ -213,13 +221,13 @@ pub(crate) fn run_in_thread_pool_with_globals<F: FnOnce() -> R + Send, R: Send>(
fn load_backend_from_dylib(path: &Path) -> MakeBackendFn {
let lib = unsafe { Library::new(path) }.unwrap_or_else(|err| {
let err = format!("couldn't load codegen backend {path:?}: {err}");
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
});
let backend_sym = unsafe { lib.get::<MakeBackendFn>(b"__rustc_codegen_backend") }
.unwrap_or_else(|e| {
let err = format!("couldn't load codegen backend: {e}");
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
});
// Intentionally leak the dynamic library. We can't ever unload it
@@ -313,7 +321,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
"failed to find a `codegen-backends` folder \
in the sysroot candidates:\n* {candidates}"
);
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
});
info!("probing {} for a codegen backend", sysroot.display());
@@ -324,7 +332,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
sysroot.display(),
e
);
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
});
let mut file: Option<PathBuf> = None;
@@ -352,7 +360,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
prev.display(),
path.display()
);
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
}
file = Some(path.clone());
}
@@ -361,7 +369,7 @@ fn get_codegen_sysroot(maybe_sysroot: &Option<PathBuf>, backend_name: &str) -> M
Some(ref s) => load_backend_from_dylib(s),
None => {
let err = format!("unsupported builtin codegen backend `{backend_name}`");
- early_error(ErrorOutputType::default(), &err);
+ early_error(ErrorOutputType::default(), err);
}
}
}
diff --git a/compiler/rustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs
index b3f4b5cd5..29335a8c0 100644
--- a/compiler/rustc_lexer/src/lib.rs
+++ b/compiler/rustc_lexer/src/lib.rs
@@ -186,12 +186,16 @@ pub enum LiteralKind {
Str { terminated: bool },
/// "b"abc"", "b"abc"
ByteStr { terminated: bool },
+ /// `c"abc"`, `c"abc`
+ CStr { terminated: bool },
/// "r"abc"", "r#"abc"#", "r####"ab"###"c"####", "r#"a". `None` indicates
/// an invalid literal.
RawStr { n_hashes: Option<u8> },
/// "br"abc"", "br#"abc"#", "br####"ab"###"c"####", "br#"a". `None`
/// indicates an invalid literal.
RawByteStr { n_hashes: Option<u8> },
+ /// `cr"abc"`, "cr#"abc"#", `cr#"a`. `None` indicates an invalid literal.
+ RawCStr { n_hashes: Option<u8> },
}
#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
@@ -357,39 +361,11 @@ impl Cursor<'_> {
},
// Byte literal, byte string literal, raw byte string literal or identifier.
- 'b' => match (self.first(), self.second()) {
- ('\'', _) => {
- self.bump();
- let terminated = self.single_quoted_string();
- let suffix_start = self.pos_within_token();
- if terminated {
- self.eat_literal_suffix();
- }
- let kind = Byte { terminated };
- Literal { kind, suffix_start }
- }
- ('"', _) => {
- self.bump();
- let terminated = self.double_quoted_string();
- let suffix_start = self.pos_within_token();
- if terminated {
- self.eat_literal_suffix();
- }
- let kind = ByteStr { terminated };
- Literal { kind, suffix_start }
- }
- ('r', '"') | ('r', '#') => {
- self.bump();
- let res = self.raw_double_quoted_string(2);
- let suffix_start = self.pos_within_token();
- if res.is_ok() {
- self.eat_literal_suffix();
- }
- let kind = RawByteStr { n_hashes: res.ok() };
- Literal { kind, suffix_start }
- }
- _ => self.ident_or_unknown_prefix(),
- },
+ 'b' => self.c_or_byte_string(
+ |terminated| ByteStr { terminated },
+ |n_hashes| RawByteStr { n_hashes },
+ Some(|terminated| Byte { terminated }),
+ ),
// Identifier (this should be checked after other variant that can
// start as identifier).
@@ -553,39 +529,84 @@ impl Cursor<'_> {
}
}
+ fn c_or_byte_string(
+ &mut self,
+ mk_kind: impl FnOnce(bool) -> LiteralKind,
+ mk_kind_raw: impl FnOnce(Option<u8>) -> LiteralKind,
+ single_quoted: Option<fn(bool) -> LiteralKind>,
+ ) -> TokenKind {
+ match (self.first(), self.second(), single_quoted) {
+ ('\'', _, Some(mk_kind)) => {
+ self.bump();
+ let terminated = self.single_quoted_string();
+ let suffix_start = self.pos_within_token();
+ if terminated {
+ self.eat_literal_suffix();
+ }
+ let kind = mk_kind(terminated);
+ Literal { kind, suffix_start }
+ }
+ ('"', _, _) => {
+ self.bump();
+ let terminated = self.double_quoted_string();
+ let suffix_start = self.pos_within_token();
+ if terminated {
+ self.eat_literal_suffix();
+ }
+ let kind = mk_kind(terminated);
+ Literal { kind, suffix_start }
+ }
+ ('r', '"', _) | ('r', '#', _) => {
+ self.bump();
+ let res = self.raw_double_quoted_string(2);
+ let suffix_start = self.pos_within_token();
+ if res.is_ok() {
+ self.eat_literal_suffix();
+ }
+ let kind = mk_kind_raw(res.ok());
+ Literal { kind, suffix_start }
+ }
+ _ => self.ident_or_unknown_prefix(),
+ }
+ }
+
fn number(&mut self, first_digit: char) -> LiteralKind {
debug_assert!('0' <= self.prev() && self.prev() <= '9');
let mut base = Base::Decimal;
if first_digit == '0' {
// Attempt to parse encoding base.
- let has_digits = match self.first() {
+ match self.first() {
'b' => {
base = Base::Binary;
self.bump();
- self.eat_decimal_digits()
+ if !self.eat_decimal_digits() {
+ return Int { base, empty_int: true };
+ }
}
'o' => {
base = Base::Octal;
self.bump();
- self.eat_decimal_digits()
+ if !self.eat_decimal_digits() {
+ return Int { base, empty_int: true };
+ }
}
'x' => {
base = Base::Hexadecimal;
self.bump();
- self.eat_hexadecimal_digits()
+ if !self.eat_hexadecimal_digits() {
+ return Int { base, empty_int: true };
+ }
}
- // Not a base prefix.
- '0'..='9' | '_' | '.' | 'e' | 'E' => {
+ // Not a base prefix; consume additional digits.
+ '0'..='9' | '_' => {
self.eat_decimal_digits();
- true
}
+
+ // Also not a base prefix; nothing more to do here.
+ '.' | 'e' | 'E' => {}
+
// Just a 0.
_ => return Int { base, empty_int: false },
- };
- // Base prefix was provided, but there were no digits
- // after it, e.g. "0x".
- if !has_digits {
- return Int { base, empty_int: true };
}
} else {
// No base prefix, parse number in the usual way.
diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs
index bb4d91247..c9ad54d8d 100644
--- a/compiler/rustc_lexer/src/unescape.rs
+++ b/compiler/rustc_lexer/src/unescape.rs
@@ -86,10 +86,45 @@ where
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(src, mode == Mode::ByteStr, callback),
+ Mode::Str | Mode::ByteStr => unescape_str_common(src, mode, callback),
+
Mode::RawStr | Mode::RawByteStr => {
unescape_raw_str_or_raw_byte_str(src, mode == Mode::RawByteStr, callback)
}
+ Mode::CStr | Mode::RawCStr => unreachable!(),
+ }
+}
+
+/// A unit within CStr. Must not be a nul character.
+pub enum CStrUnit {
+ Byte(u8),
+ Char(char),
+}
+
+impl From<u8> for CStrUnit {
+ fn from(value: u8) -> Self {
+ CStrUnit::Byte(value)
+ }
+}
+
+impl From<char> for CStrUnit {
+ fn from(value: char) -> Self {
+ CStrUnit::Char(value)
+ }
+}
+
+pub fn unescape_c_string<F>(src: &str, mode: Mode, callback: &mut F)
+where
+ F: FnMut(Range<usize>, Result<CStrUnit, EscapeError>),
+{
+ if mode == Mode::RawCStr {
+ unescape_raw_str_or_raw_byte_str(
+ src,
+ mode.characters_should_be_ascii(),
+ &mut |r, result| callback(r, result.map(CStrUnit::Char)),
+ );
+ } else {
+ unescape_str_common(src, mode, callback);
}
}
@@ -114,34 +149,69 @@ pub enum Mode {
ByteStr,
RawStr,
RawByteStr,
+ CStr,
+ RawCStr,
}
impl Mode {
pub fn in_double_quotes(self) -> bool {
match self {
- Mode::Str | Mode::ByteStr | Mode::RawStr | Mode::RawByteStr => true,
+ Mode::Str
+ | Mode::ByteStr
+ | Mode::RawStr
+ | Mode::RawByteStr
+ | Mode::CStr
+ | Mode::RawCStr => true,
Mode::Char | Mode::Byte => false,
}
}
- pub fn is_byte(self) -> bool {
+ /// Non-byte literals should have `\xXX` escapes that are within the ASCII range.
+ pub fn ascii_escapes_should_be_ascii(self) -> bool {
+ match self {
+ Mode::Char | Mode::Str | Mode::RawStr => true,
+ Mode::Byte | Mode::ByteStr | Mode::RawByteStr | Mode::CStr | Mode::RawCStr => false,
+ }
+ }
+
+ /// Whether characters within the literal must be within the ASCII range
+ pub fn characters_should_be_ascii(self) -> bool {
+ match self {
+ Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
+ Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+ }
+ }
+
+ /// Byte literals do not allow unicode escape.
+ pub fn is_unicode_escape_disallowed(self) -> bool {
match self {
Mode::Byte | Mode::ByteStr | Mode::RawByteStr => true,
- Mode::Char | Mode::Str | Mode::RawStr => false,
+ Mode::Char | Mode::Str | Mode::RawStr | Mode::CStr | Mode::RawCStr => false,
+ }
+ }
+
+ pub fn prefix_noraw(self) -> &'static str {
+ match self {
+ Mode::Byte | Mode::ByteStr | Mode::RawByteStr => "b",
+ Mode::CStr | Mode::RawCStr => "c",
+ Mode::Char | Mode::Str | Mode::RawStr => "",
}
}
}
-fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError> {
+fn scan_escape<T: From<u8> + From<char>>(
+ chars: &mut Chars<'_>,
+ mode: Mode,
+) -> Result<T, EscapeError> {
// Previous character was '\\', unescape what follows.
let res = match chars.next().ok_or(EscapeError::LoneSlash)? {
- '"' => '"',
- 'n' => '\n',
- 'r' => '\r',
- 't' => '\t',
- '\\' => '\\',
- '\'' => '\'',
- '0' => '\0',
+ '"' => b'"',
+ 'n' => b'\n',
+ 'r' => b'\r',
+ 't' => b'\t',
+ '\\' => b'\\',
+ '\'' => b'\'',
+ '0' => b'\0',
'x' => {
// Parse hexadecimal character code.
@@ -154,76 +224,78 @@ fn scan_escape(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, EscapeError
let value = hi * 16 + lo;
- // For a non-byte literal verify that it is within ASCII range.
- if !is_byte && !is_ascii(value) {
+ if mode.ascii_escapes_should_be_ascii() && !is_ascii(value) {
return Err(EscapeError::OutOfRangeHexEscape);
}
- let value = value as u8;
- value as char
+ value as u8
}
- 'u' => {
- // We've parsed '\u', now we have to parse '{..}'.
+ 'u' => return scan_unicode(chars, mode.is_unicode_escape_disallowed()).map(Into::into),
+ _ => return Err(EscapeError::InvalidEscape),
+ };
+ Ok(res.into())
+}
+
+fn scan_unicode(
+ chars: &mut Chars<'_>,
+ is_unicode_escape_disallowed: bool,
+) -> Result<char, EscapeError> {
+ // We've parsed '\u', now we have to parse '{..}'.
- if chars.next() != Some('{') {
- return Err(EscapeError::NoBraceInUnicodeEscape);
- }
+ if chars.next() != Some('{') {
+ return Err(EscapeError::NoBraceInUnicodeEscape);
+ }
- // First character must be a hexadecimal digit.
- let mut n_digits = 1;
- let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
- '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
- '}' => return Err(EscapeError::EmptyUnicodeEscape),
- c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
- };
-
- // First character is valid, now parse the rest of the number
- // and closing brace.
- loop {
- match chars.next() {
- None => return Err(EscapeError::UnclosedUnicodeEscape),
- Some('_') => continue,
- Some('}') => {
- if n_digits > 6 {
- return Err(EscapeError::OverlongUnicodeEscape);
- }
-
- // Incorrect syntax has higher priority for error reporting
- // than unallowed value for a literal.
- if is_byte {
- return Err(EscapeError::UnicodeEscapeInByte);
- }
-
- break std::char::from_u32(value).ok_or_else(|| {
- if value > 0x10FFFF {
- EscapeError::OutOfRangeUnicodeEscape
- } else {
- EscapeError::LoneSurrogateUnicodeEscape
- }
- })?;
- }
- Some(c) => {
- let digit: u32 =
- c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
- n_digits += 1;
- if n_digits > 6 {
- // Stop updating value since we're sure that it's incorrect already.
- continue;
- }
- value = value * 16 + digit;
+ // First character must be a hexadecimal digit.
+ let mut n_digits = 1;
+ let mut value: u32 = match chars.next().ok_or(EscapeError::UnclosedUnicodeEscape)? {
+ '_' => return Err(EscapeError::LeadingUnderscoreUnicodeEscape),
+ '}' => return Err(EscapeError::EmptyUnicodeEscape),
+ c => c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?,
+ };
+
+ // First character is valid, now parse the rest of the number
+ // and closing brace.
+ loop {
+ match chars.next() {
+ None => return Err(EscapeError::UnclosedUnicodeEscape),
+ Some('_') => continue,
+ Some('}') => {
+ if n_digits > 6 {
+ return Err(EscapeError::OverlongUnicodeEscape);
+ }
+
+ // Incorrect syntax has higher priority for error reporting
+ // than unallowed value for a literal.
+ if is_unicode_escape_disallowed {
+ return Err(EscapeError::UnicodeEscapeInByte);
+ }
+
+ break std::char::from_u32(value).ok_or_else(|| {
+ if value > 0x10FFFF {
+ EscapeError::OutOfRangeUnicodeEscape
+ } else {
+ EscapeError::LoneSurrogateUnicodeEscape
}
- };
+ });
}
- }
- _ => return Err(EscapeError::InvalidEscape),
- };
- Ok(res)
+ Some(c) => {
+ let digit: u32 = c.to_digit(16).ok_or(EscapeError::InvalidCharInUnicodeEscape)?;
+ n_digits += 1;
+ if n_digits > 6 {
+ // Stop updating value since we're sure that it's incorrect already.
+ continue;
+ }
+ value = value * 16 + digit;
+ }
+ };
+ }
}
#[inline]
-fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
- if is_byte && !c.is_ascii() {
+fn ascii_check(c: char, characters_should_be_ascii: bool) -> Result<char, EscapeError> {
+ if characters_should_be_ascii && !c.is_ascii() {
// Byte literal can't be a non-ascii character.
Err(EscapeError::NonAsciiCharInByte)
} else {
@@ -234,7 +306,7 @@ fn ascii_check(c: char, is_byte: bool) -> Result<char, EscapeError> {
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),
+ '\\' => scan_escape(chars, if is_byte { Mode::Byte } else { Mode::Char }),
'\n' | '\t' | '\'' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn),
_ => ascii_check(c, is_byte),
@@ -247,9 +319,9 @@ fn unescape_char_or_byte(chars: &mut Chars<'_>, is_byte: bool) -> Result<char, E
/// 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, is_byte: bool, callback: &mut F)
+fn unescape_str_common<F, T: From<u8> + From<char>>(src: &str, mode: Mode, callback: &mut F)
where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
+ F: FnMut(Range<usize>, Result<T, EscapeError>),
{
let mut chars = src.chars();
@@ -266,47 +338,49 @@ where
// if unescaped '\' character is followed by '\n'.
// For details see [Rust language reference]
// (https://doc.rust-lang.org/reference/tokens.html#string-literals).
- skip_ascii_whitespace(&mut chars, start, callback);
+ skip_ascii_whitespace(&mut chars, start, &mut |range, err| {
+ callback(range, Err(err))
+ });
continue;
}
- _ => scan_escape(&mut chars, is_byte),
+ _ => scan_escape::<T>(&mut chars, mode),
}
}
- '\n' => Ok('\n'),
- '\t' => Ok('\t'),
+ '\n' => Ok(b'\n'.into()),
+ '\t' => Ok(b'\t'.into()),
'"' => Err(EscapeError::EscapeOnlyChar),
'\r' => Err(EscapeError::BareCarriageReturn),
- _ => ascii_check(c, is_byte),
+ _ => ascii_check(c, mode.characters_should_be_ascii()).map(Into::into),
};
let end = src.len() - chars.as_str().len();
- callback(start..end, res);
+ callback(start..end, res.map(Into::into));
}
+}
- fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
- where
- F: FnMut(Range<usize>, Result<char, EscapeError>),
- {
- let tail = chars.as_str();
- let first_non_space = tail
- .bytes()
- .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
- .unwrap_or(tail.len());
- if tail[1..first_non_space].contains('\n') {
- // The +1 accounts for the escaping slash.
- let end = start + first_non_space + 1;
- callback(start..end, Err(EscapeError::MultipleSkippedLinesWarning));
- }
- let tail = &tail[first_non_space..];
- if let Some(c) = tail.chars().nth(0) {
- if c.is_whitespace() {
- // For error reporting, we would like the span to contain the character that was not
- // skipped. The +1 is necessary to account for the leading \ that started the escape.
- let end = start + first_non_space + c.len_utf8() + 1;
- callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning));
- }
+fn skip_ascii_whitespace<F>(chars: &mut Chars<'_>, start: usize, callback: &mut F)
+where
+ F: FnMut(Range<usize>, EscapeError),
+{
+ let tail = chars.as_str();
+ let first_non_space = tail
+ .bytes()
+ .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r')
+ .unwrap_or(tail.len());
+ if tail[1..first_non_space].contains('\n') {
+ // The +1 accounts for the escaping slash.
+ let end = start + first_non_space + 1;
+ callback(start..end, EscapeError::MultipleSkippedLinesWarning);
+ }
+ let tail = &tail[first_non_space..];
+ if let Some(c) = tail.chars().nth(0) {
+ if c.is_whitespace() {
+ // For error reporting, we would like the span to contain the character that was not
+ // skipped. The +1 is necessary to account for the leading \ that started the escape.
+ let end = start + first_non_space + c.len_utf8() + 1;
+ callback(start..end, EscapeError::UnskippedWhitespaceWarning);
}
- *chars = tail.chars();
}
+ *chars = tail.chars();
}
/// Takes a contents of a string literal (without quotes) and produces a
diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml
index abe61406c..539eea3d8 100644
--- a/compiler/rustc_lint/Cargo.toml
+++ b/compiler/rustc_lint/Cargo.toml
@@ -11,6 +11,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_attr = { path = "../rustc_attr" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_lint/messages.ftl b/compiler/rustc_lint/messages.ftl
index db15b176d..0fa67cdb3 100644
--- a/compiler/rustc_lint/messages.ftl
+++ b/compiler/rustc_lint/messages.ftl
@@ -5,6 +5,202 @@ lint_array_into_iter =
.use_explicit_into_iter_suggestion =
or use `IntoIterator::into_iter(..)` instead of `.into_iter()` to explicitly iterate by value
+lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
+ .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+
+lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write
+ .label = invalid failure ordering
+ .help = consider using `Acquire` or `Relaxed` failure ordering instead
+
+lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering
+ .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+
+lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
+ .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+
+lint_bad_attribute_argument = bad attribute argument
+
+lint_bad_opt_access = {$msg}
+
+lint_builtin_allow_internal_unsafe =
+ `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
+
+lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition
+ .suggestion = try naming the parameter or explicitly ignoring it
+
+lint_builtin_asm_labels = avoid using named labels in inline assembly
+
+lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
+
+lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
+ .previous_decl_label = `{$orig}` previously declared here
+ .mismatch_label = this signature doesn't match the previous declaration
+
+lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
+ .previous_decl_label = `{$orig}` previously declared here
+ .mismatch_label = this signature doesn't match the previous declaration
+lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
+ .suggestion = try a static value
+
+lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
+lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
+lint_builtin_deprecated_attr_default_suggestion = remove this attribute
+
+lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
+ .msg_suggestion = {$msg}
+ .default_suggestion = remove this attribute
+lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
+lint_builtin_deref_nullptr = dereferencing a null pointer
+ .label = this code causes undefined behavior when executed
+
+lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
+ .suggestion = use `..=` for an inclusive range
+
+lint_builtin_explicit_outlives = outlives requirements can be inferred
+ .suggestion = remove {$count ->
+ [one] this bound
+ *[other] these bounds
+ }
+
+lint_builtin_export_name_fn = declaration of a function with `export_name`
+lint_builtin_export_name_method = declaration of a method with `export_name`
+
+lint_builtin_export_name_static = declaration of a static with `export_name`
+lint_builtin_impl_unsafe_method = implementation of an `unsafe` method
+
+lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
+ .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
+ .help = consider using `min_{$name}` instead, which is more stable and complete
+
+lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition
+ .suggestion = you can use a raw identifier to stay compatible
+
+lint_builtin_link_section_fn = declaration of a function with `link_section`
+
+lint_builtin_link_section_static = declaration of a static with `link_section`
+
+lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy`
+
+lint_builtin_missing_debug_impl =
+ type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation
+
+lint_builtin_missing_doc = missing documentation for {$article} {$desc}
+
+lint_builtin_mutable_transmutes =
+ transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
+
+lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
+lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
+ .suggestion = remove this attribute
+
+lint_builtin_no_mangle_method = declaration of a `no_mangle` method
+lint_builtin_no_mangle_static = declaration of a `no_mangle` static
+lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant
+ .suggestion = use shorthand field pattern
+
+lint_builtin_overridden_symbol_name =
+ the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
+
+lint_builtin_overridden_symbol_section =
+ the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them
+
+lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
+ .note = lib.rs is the root of this crate's library target
+ .help = to refer to it from other targets, use the library's name as the path
+
+lint_builtin_special_module_name_used_main = found module declaration for main.rs
+ .note = a binary crate cannot be used as library
+
+lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
+
+lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
+
+lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases
+ .suggestion = the bound will not be checked when the type alias is used, and should be removed
+
+lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
+ .suggestion = the clause will not be checked when the type alias is used, and should be removed
+
+lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
+
+lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
+ .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
+
+lint_builtin_unnameable_test_items = cannot test inner items
+
+lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
+lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
+
+lint_builtin_unpermitted_type_init_uninit = the type `{$ty}` does not permit being left uninitialized
+
+lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
+lint_builtin_unreachable_pub = unreachable `pub` {$what}
+ .suggestion = consider restricting its visibility
+ .help = or consider exporting it for use by other crates
+
+lint_builtin_unsafe_block = usage of an `unsafe` block
+
+lint_builtin_unsafe_impl = implementation of an `unsafe` trait
+
+lint_builtin_unsafe_trait = declaration of an `unsafe` trait
+
+lint_builtin_unstable_features = unstable feature
+
+lint_builtin_unused_doc_comment = unused doc comment
+ .label = rustdoc does not generate documentation for {$kind}
+ .plain_help = use `//` for a plain comment
+ .block_help = use `/* */` for a plain comment
+
+lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
+ .suggestion = use `loop`
+
+lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+
+lint_check_name_unknown = unknown lint: `{$lint_name}`
+ .help = did you mean: `{$suggestion}`
+
+lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+
+lint_check_name_warning = {$msg}
+
+lint_command_line_source = `forbid` lint level was set on command line
+
+lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
+ .label = this is where the previous identifier occurred
+
+lint_cstring_ptr = getting the inner pointer of a temporary `CString`
+ .as_ptr_label = this pointer will be invalid
+ .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
+ .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
+ .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
+
+lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
+ .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
+
+lint_default_source = `forbid` lint level is the default for {$id}
+
+lint_deprecated_lint_name =
+ lint name `{$name}` is deprecated and may not have an effect in the future.
+ .suggestion = change it to
+
+lint_diag_out_of_impl =
+ diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
+
+lint_drop_glue =
+ types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
+
+lint_drop_trait_constraints =
+ bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped
+
+lint_dropping_copy_types = calls to `std::mem::drop` with a value that implements `Copy` does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+
+lint_dropping_references = calls to `std::mem::drop` with a reference instead of an owned value does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+
lint_enum_intrinsics_mem_discriminant =
the return value of `mem::discriminant` is unspecified when called with a non-enum type
.note = the argument to `discriminant` should be a reference to an enum, but it was passed a reference to a `{$ty_param}`, which is not an enum.
@@ -24,41 +220,12 @@ lint_for_loops_over_fallibles =
.use_while_let = to check pattern in a loop use `while let`
.use_question_mark = consider unwrapping the `Result` with `?` to iterate over its contents
-lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
- .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
- .function_label = this function returns `()`, which is likely not what you wanted
- .argument_label = called `Iterator::map` with callable that returns `()`
- .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
- .suggestion = you might have meant to use `Iterator::for_each`
-
-lint_non_binding_let_on_sync_lock =
- non-binding let on a synchronization lock
-
-lint_non_binding_let_on_drop_type =
- non-binding let on a type that implements `Drop`
-
-lint_non_binding_let_suggestion =
- consider binding to an unused variable to avoid immediately dropping the value
-
-lint_non_binding_let_multi_suggestion =
- consider immediately dropping the value
-
-lint_deprecated_lint_name =
- lint name `{$name}` is deprecated and may not have an effect in the future.
- .suggestion = change it to
-
-lint_renamed_or_removed_lint = {$msg}
- .suggestion = use the new name
-
-lint_unknown_lint =
- unknown lint: `{$name}`
- .suggestion = did you mean
-
-lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
-
-lint_unknown_gated_lint =
- unknown lint: `{$name}`
- .note = the `{$name}` lint is unstable
+lint_forgetting_copy_types = calls to `std::mem::forget` with a value that implements `Copy` does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
+lint_forgetting_references = calls to `std::mem::forget` with a reference instead of an owned value does nothing
+ .label = argument has type `{$arg_ty}`
+ .note = use `let _ = ...` to ignore the expression or result
lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of text present in {$label}
.label = this {$label} contains {$count ->
@@ -73,54 +240,111 @@ lint_hidden_unicode_codepoints = unicode codepoint changing visible direction of
.suggestion_escape = if you want to keep them but make them visible in your source code, you can escape them
.no_suggestion_note_escape = if you want to keep them but make them visible in your source code, you can escape them: {$escaped}
-lint_default_hash_types = prefer `{$preferred}` over `{$used}`, it has better performance
- .note = a `use rustc_data_structures::fx::{$preferred}` may be necessary
+lint_identifier_non_ascii_char = identifier contains non-ASCII characters
-lint_query_instability = using `{$query}` can result in unstable query results
- .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
+lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
-lint_tykind_kind = usage of `ty::TyKind::<kind>`
- .suggestion = try using `ty::<kind>` directly
+lint_ignored_unless_crate_specified = {$level}({$name}) is ignored unless specified at crate level
-lint_tykind = usage of `ty::TyKind`
- .help = try using `Ty` instead
+lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
+ .label = not FFI-safe
+ .note = the type is defined here
-lint_ty_qualified = usage of qualified `ty::{$ty}`
- .suggestion = try importing it and using it unqualified
+lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
-lint_lintpass_by_hand = implementing `LintPass` by hand
- .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+lint_improper_ctypes_array_help = consider passing a pointer to the array
-lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
- .help = only existing keywords are allowed in core/std
+lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
+lint_improper_ctypes_box = box cannot be represented as a single pointer
-lint_diag_out_of_impl =
- diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls
+lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
-lint_untranslatable_diag = diagnostics should be created using translatable messages
+lint_improper_ctypes_char_reason = the `char` type has no C equivalent
+lint_improper_ctypes_dyn = trait objects have no C equivalent
-lint_bad_opt_access = {$msg}
+lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
-lint_cstring_ptr = getting the inner pointer of a temporary `CString`
- .as_ptr_label = this pointer will be invalid
- .unwrap_label = this `CString` is deallocated at the end of the statement, bind it to a variable to extend its lifetime
- .note = pointers do not have a lifetime; when calling `as_ptr` the `CString` will be deallocated at the end of the statement because nothing is referencing it as far as the type system is concerned
- .help = for more information, see https://doc.rust-lang.org/reference/destructors.html
+lint_improper_ctypes_enum_repr_help =
+ consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
-lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+lint_improper_ctypes_enum_repr_reason = enum has no representation hint
+lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
-lint_identifier_non_ascii_char = identifier contains non-ASCII characters
+lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
+lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
+lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
-lint_identifier_uncommon_codepoints = identifier contains uncommon Unicode codepoints
+lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
-lint_confusable_identifier_pair = identifier pair considered confusable between `{$existing_sym}` and `{$sym}`
- .label = this is where the previous identifier occurred
+lint_improper_ctypes_opaque = opaque types have no C equivalent
+
+lint_improper_ctypes_slice_help = consider using a raw pointer instead
+
+lint_improper_ctypes_slice_reason = slices have no C equivalent
+lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
+
+lint_improper_ctypes_str_reason = string slices have no C equivalent
+lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct
+
+lint_improper_ctypes_struct_fieldless_reason = this struct has no fields
+lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+
+lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout
+lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
+lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+
+lint_improper_ctypes_tuple_help = consider using a struct instead
+
+lint_improper_ctypes_tuple_reason = tuples have unspecified layout
+lint_improper_ctypes_union_fieldless_help = consider adding a member to this union
+
+lint_improper_ctypes_union_fieldless_reason = this union has no fields
+lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+
+lint_improper_ctypes_union_layout_reason = this union has unspecified layout
+lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+
+lint_lintpass_by_hand = implementing `LintPass` by hand
+ .help = try using `declare_lint_pass!` or `impl_lint_pass!` instead
+
+lint_malformed_attribute = malformed lint attribute input
+
+lint_map_unit_fn = `Iterator::map` call that discard the iterator's values
+ .note = `Iterator::map`, like many of the methods on `Iterator`, gets executed lazily, meaning that its effects won't be visible until it is iterated
+ .function_label = this function returns `()`, which is likely not what you wanted
+ .argument_label = called `Iterator::map` with callable that returns `()`
+ .map_label = after this call to map, the resulting iterator is `impl Iterator<Item = ()>`, which means the only information carried by the iterator is the number of items
+ .suggestion = you might have meant to use `Iterator::for_each`
lint_mixed_script_confusables =
the usage of Script Group `{$set}` in this crate consists solely of mixed script confusables
.includes_note = the usage includes {$includes}
.note = please recheck to make sure their usages are indeed what you want
+lint_multiple_supertrait_upcastable = `{$ident}` is object-safe and has multiple supertraits
+
+lint_node_source = `forbid` level set here
+ .note = {$reason}
+
+lint_non_binding_let_multi_suggestion =
+ consider immediately dropping the value
+
+lint_non_binding_let_on_drop_type =
+ non-binding let on a type that implements `Drop`
+
+lint_non_binding_let_on_sync_lock =
+ non-binding let on a synchronization lock
+
+lint_non_binding_let_suggestion =
+ consider binding to an unused variable to avoid immediately dropping the value
+
+lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name
+ .suggestion = convert the identifier to upper camel case
+ .label = should have an UpperCamelCase name
+
+lint_non_existent_doc_keyword = found non-existing keyword `{$keyword}` used in `#[doc(keyword = "...")]`
+ .help = only existing keywords are allowed in core/std
+
lint_non_fmt_panic = panic message is not a string literal
.note = this usage of `{$name}!()` is deprecated; it will be a hard error in Rust 2021
.more_info_note = for more information, see <https://doc.rust-lang.org/nightly/edition-guide/rust-2021/panic-macro-consistency.html>
@@ -134,6 +358,14 @@ lint_non_fmt_panic = panic message is not a string literal
*[false] use
} std::panic::panic_any instead
+lint_non_fmt_panic_braces =
+ panic message contains {$count ->
+ [one] a brace
+ *[other] braces
+ }
+ .note = this message is not used as a format string, but will be in Rust 2021
+ .suggestion = add a "{"{"}{"}"}" format string to use the message literally
+
lint_non_fmt_panic_unused =
panic message contains {$count ->
[one] an unused
@@ -149,18 +381,6 @@ lint_non_fmt_panic_unused =
}
.add_fmt_suggestion = or add a "{"{"}{"}"}" format string to use the message literally
-lint_non_fmt_panic_braces =
- panic message contains {$count ->
- [one] a brace
- *[other] braces
- }
- .note = this message is not used as a format string, but will be in Rust 2021
- .suggestion = add a "{"{"}{"}"}" format string to use the message literally
-
-lint_non_camel_case_type = {$sort} `{$name}` should have an upper camel case name
- .suggestion = convert the identifier to upper camel case
- .label = should have an UpperCamelCase name
-
lint_non_snake_case = {$sort} `{$name}` should have a snake case name
.rename_or_convert_suggestion = rename the identifier or convert it to a snake case raw identifier
.cannot_convert_note = `{$sc}` cannot be used as a raw identifier
@@ -177,29 +397,13 @@ lint_noop_method_call = call to `.{$method}()` on a reference in this situation
.label = unnecessary method call
.note = the type `{$receiver_ty}` which `{$method}` is being called on is the same as the type returned from `{$method}`, so the method call does not do anything and can be removed
-lint_pass_by_value = passing `{$ty}` by reference
- .suggestion = try passing by value
-
-lint_redundant_semicolons =
- unnecessary trailing {$multiple ->
- [true] semicolons
- *[false] semicolon
- }
- .suggestion = remove {$multiple ->
- [true] these semicolons
- *[false] this semicolon
- }
-
-lint_drop_trait_constraints =
- bounds on `{$predicate}` are most likely incorrect, consider instead using `{$needs_drop}` to detect whether a type can be trivially dropped
-
-lint_drop_glue =
- types that do not implement `Drop` can still have drop glue, consider instead using `{$needs_drop}` to detect whether a type is trivially dropped
-
-lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
+lint_only_cast_u8_to_char = only `u8` can be cast into `char`
+ .suggestion = use a `char` literal instead
-lint_range_use_inclusive_range = use an inclusive range instead
+lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
+ .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
+lint_opaque_hidden_inferred_bound_sugg = add this bound
lint_overflowing_bin_hex = literal out of range for `{$ty}`
.negative_note = the literal `{$lit}` (decimal `{$dec}`) does not fit into the type `{$ty}`
@@ -212,96 +416,90 @@ lint_overflowing_int = literal out of range for `{$ty}`
.note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
.help = consider using the type `{$suggestion_ty}` instead
-lint_only_cast_u8_to_char = only `u8` can be cast into `char`
- .suggestion = use a `char` literal instead
-
-lint_overflowing_uint = literal out of range for `{$ty}`
- .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
-
lint_overflowing_literal = literal out of range for `{$ty}`
.note = the literal `{$lit}` does not fit into the type `{$ty}` and will be converted to `{$ty}::INFINITY`
-lint_unused_comparisons = comparison is useless due to type limits
-
-lint_improper_ctypes = `extern` {$desc} uses type `{$ty}`, which is not FFI-safe
- .label = not FFI-safe
- .note = the type is defined here
+lint_overflowing_uint = literal out of range for `{$ty}`
+ .note = the literal `{$lit}` does not fit into the type `{$ty}` whose range is `{$min}..={$max}`
-lint_improper_ctypes_opaque = opaque types have no C equivalent
+lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
+ .label = overruled by previous forbid
-lint_improper_ctypes_fnptr_reason = this function pointer has Rust-specific calling convention
-lint_improper_ctypes_fnptr_help = consider using an `extern fn(...) -> ...` function pointer instead
+lint_pass_by_value = passing `{$ty}` by reference
+ .suggestion = try passing by value
-lint_improper_ctypes_tuple_reason = tuples have unspecified layout
-lint_improper_ctypes_tuple_help = consider using a struct instead
+lint_path_statement_drop = path statement drops value
+ .suggestion = use `drop` to clarify the intent
-lint_improper_ctypes_str_reason = string slices have no C equivalent
-lint_improper_ctypes_str_help = consider using `*const u8` and a length instead
+lint_path_statement_no_effect = path statement with no effect
-lint_improper_ctypes_dyn = trait objects have no C equivalent
+lint_query_instability = using `{$query}` can result in unstable query results
+ .note = if you believe this case to be fine, allow this lint and add a comment explaining your rationale
-lint_improper_ctypes_slice_reason = slices have no C equivalent
-lint_improper_ctypes_slice_help = consider using a raw pointer instead
+lint_range_endpoint_out_of_range = range endpoint is out of range for `{$ty}`
-lint_improper_ctypes_128bit = 128-bit integers don't currently have a known stable ABI
+lint_range_use_inclusive_range = use an inclusive range instead
-lint_improper_ctypes_char_reason = the `char` type has no C equivalent
-lint_improper_ctypes_char_help = consider using `u32` or `libc::wchar_t` instead
-lint_improper_ctypes_non_exhaustive = this enum is non-exhaustive
-lint_improper_ctypes_non_exhaustive_variant = this enum has non-exhaustive variants
+lint_reason_must_be_string_literal = reason must be a string literal
-lint_improper_ctypes_enum_repr_reason = enum has no representation hint
-lint_improper_ctypes_enum_repr_help =
- consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum
+lint_reason_must_come_last = reason in lint attribute must come last
-lint_improper_ctypes_struct_fieldless_reason = this struct has no fields
-lint_improper_ctypes_struct_fieldless_help = consider adding a member to this struct
+lint_redundant_semicolons =
+ unnecessary trailing {$multiple ->
+ [true] semicolons
+ *[false] semicolon
+ }
+ .suggestion = remove {$multiple ->
+ [true] these semicolons
+ *[false] this semicolon
+ }
-lint_improper_ctypes_union_fieldless_reason = this union has no fields
-lint_improper_ctypes_union_fieldless_help = consider adding a member to this union
+lint_renamed_or_removed_lint = {$msg}
+ .suggestion = use the new name
-lint_improper_ctypes_struct_non_exhaustive = this struct is non-exhaustive
-lint_improper_ctypes_union_non_exhaustive = this union is non-exhaustive
+lint_requested_level = requested on the command line with `{$level} {$lint_name}`
-lint_improper_ctypes_struct_layout_reason = this struct has unspecified layout
-lint_improper_ctypes_struct_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct
+lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
+ .label = target type is set here
-lint_improper_ctypes_union_layout_reason = this union has unspecified layout
-lint_improper_ctypes_union_layout_help = consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this union
+lint_suspicious_double_ref_clone =
+ using `.clone()` on a double reference, which returns `{$ty}` instead of cloning the inner type
-lint_improper_ctypes_box = box cannot be represented as a single pointer
+lint_suspicious_double_ref_deref =
+ using `.deref()` on a double reference, which returns `{$ty}` instead of dereferencing the inner type
-lint_improper_ctypes_enum_phantomdata = this enum contains a PhantomData field
+lint_trivial_untranslatable_diag = diagnostic with static strings only
-lint_improper_ctypes_struct_zst = this struct contains only zero-sized fields
+lint_ty_qualified = usage of qualified `ty::{$ty}`
+ .suggestion = try importing it and using it unqualified
-lint_improper_ctypes_array_reason = passing raw arrays by value is not FFI-safe
-lint_improper_ctypes_array_help = consider passing a pointer to the array
+lint_tykind = usage of `ty::TyKind`
+ .help = try using `Ty` instead
-lint_improper_ctypes_only_phantomdata = composed only of `PhantomData`
+lint_tykind_kind = usage of `ty::TyKind::<kind>`
+ .suggestion = try using `ty::<kind>` directly
-lint_variant_size_differences =
- enum variant is more than three times larger ({$largest} bytes) than the next largest
+lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
+ .label = this function will not propagate the caller location
-lint_atomic_ordering_load = atomic loads cannot have `Release` or `AcqRel` ordering
- .help = consider using ordering modes `Acquire`, `SeqCst` or `Relaxed`
+lint_unknown_gated_lint =
+ unknown lint: `{$name}`
+ .note = the `{$name}` lint is unstable
-lint_atomic_ordering_store = atomic stores cannot have `Acquire` or `AcqRel` ordering
- .help = consider using ordering modes `Release`, `SeqCst` or `Relaxed`
+lint_unknown_lint =
+ unknown lint: `{$name}`
+ .suggestion = did you mean
-lint_atomic_ordering_fence = memory fences cannot have `Relaxed` ordering
- .help = consider using ordering modes `Acquire`, `Release`, `AcqRel` or `SeqCst`
+lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
+ .help = add `#![register_tool({$tool_name})]` to the crate root
-lint_atomic_ordering_invalid = `{$method}`'s failure ordering may not be `Release` or `AcqRel`, since a failed `{$method}` does not result in a write
- .label = invalid failure ordering
- .help = consider using `Acquire` or `Relaxed` failure ordering instead
+lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
-lint_unused_op = unused {$op} that must be used
- .label = the {$op} produces a value
- .suggestion = use `let _ = ...` to ignore the resulting value
+lint_untranslatable_diag = diagnostics should be created using translatable messages
-lint_unused_result = unused result of type `{$ty}`
+lint_unused_allocation = unnecessary allocation, use `&` instead
+lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
lint_unused_closure =
unused {$pre}{$count ->
@@ -310,203 +508,28 @@ lint_unused_closure =
}{$post} that must be used
.note = closures are lazy and do nothing unless called
-lint_unused_generator =
- unused {$pre}{$count ->
- [one] generator
- *[other] generator
- }{$post} that must be used
- .note = generators are lazy and do nothing unless resumed
+lint_unused_comparisons = comparison is useless due to type limits
lint_unused_def = unused {$pre}`{$def}`{$post} that must be used
.suggestion = use `let _ = ...` to ignore the resulting value
-lint_path_statement_drop = path statement drops value
- .suggestion = use `drop` to clarify the intent
-
-lint_path_statement_no_effect = path statement with no effect
-
lint_unused_delim = unnecessary {$delim} around {$item}
.suggestion = remove these {$delim}
-lint_unused_import_braces = braces around {$node} is unnecessary
-
-lint_unused_allocation = unnecessary allocation, use `&` instead
-lint_unused_allocation_mut = unnecessary allocation, use `&mut` instead
-
-lint_builtin_while_true = denote infinite loops with `loop {"{"} ... {"}"}`
- .suggestion = use `loop`
-
-lint_builtin_box_pointers = type uses owned (Box type) pointers: {$ty}
-
-lint_builtin_non_shorthand_field_patterns = the `{$ident}:` in this pattern is redundant
- .suggestion = use shorthand field pattern
-
-lint_builtin_overridden_symbol_name =
- the linker's behavior with multiple libraries exporting duplicate symbol names is undefined and Rust cannot provide guarantees when you manually override them
-
-lint_builtin_overridden_symbol_section =
- the program's behavior with overridden link sections on items is unpredictable and Rust cannot provide guarantees when you manually override them
-
-lint_builtin_allow_internal_unsafe =
- `allow_internal_unsafe` allows defining macros using unsafe without triggering the `unsafe_code` lint at their call site
-
-lint_builtin_unsafe_block = usage of an `unsafe` block
-
-lint_builtin_unsafe_trait = declaration of an `unsafe` trait
-
-lint_builtin_unsafe_impl = implementation of an `unsafe` trait
-
-lint_builtin_no_mangle_fn = declaration of a `no_mangle` function
-lint_builtin_export_name_fn = declaration of a function with `export_name`
-lint_builtin_link_section_fn = declaration of a function with `link_section`
-
-lint_builtin_no_mangle_static = declaration of a `no_mangle` static
-lint_builtin_export_name_static = declaration of a static with `export_name`
-lint_builtin_link_section_static = declaration of a static with `link_section`
-
-lint_builtin_no_mangle_method = declaration of a `no_mangle` method
-lint_builtin_export_name_method = declaration of a method with `export_name`
-
-lint_builtin_decl_unsafe_fn = declaration of an `unsafe` function
-lint_builtin_decl_unsafe_method = declaration of an `unsafe` method
-lint_builtin_impl_unsafe_method = implementation of an `unsafe` method
-
-lint_builtin_missing_doc = missing documentation for {$article} {$desc}
-
-lint_builtin_missing_copy_impl = type could implement `Copy`; consider adding `impl Copy`
-
-lint_builtin_missing_debug_impl =
- type does not implement `{$debug}`; consider adding `#[derive(Debug)]` or a manual implementation
-
-lint_builtin_anonymous_params = anonymous parameters are deprecated and will be removed in the next edition
- .suggestion = try naming the parameter or explicitly ignoring it
-
-lint_builtin_deprecated_attr_link = use of deprecated attribute `{$name}`: {$reason}. See {$link}
- .msg_suggestion = {$msg}
- .default_suggestion = remove this attribute
-lint_builtin_deprecated_attr_used = use of deprecated attribute `{$name}`: no longer used.
-lint_builtin_deprecated_attr_default_suggestion = remove this attribute
-
-lint_builtin_unused_doc_comment = unused doc comment
- .label = rustdoc does not generate documentation for {$kind}
- .plain_help = use `//` for a plain comment
- .block_help = use `/* */` for a plain comment
-
-lint_builtin_no_mangle_generic = functions generic over types or consts must be mangled
- .suggestion = remove this attribute
-
-lint_builtin_const_no_mangle = const items should never be `#[no_mangle]`
- .suggestion = try a static value
-
-lint_builtin_mutable_transmutes =
- transmuting &T to &mut T is undefined behavior, even if the reference is unused, consider instead using an UnsafeCell
-
-lint_builtin_unstable_features = unstable feature
-
-lint_ungated_async_fn_track_caller = `#[track_caller]` on async functions is a no-op
- .label = this function will not propagate the caller location
-
-lint_builtin_unreachable_pub = unreachable `pub` {$what}
- .suggestion = consider restricting its visibility
- .help = or consider exporting it for use by other crates
-
-lint_builtin_unexpected_cli_config_name = unexpected `{$name}` as condition name
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected names
-
-lint_builtin_unexpected_cli_config_value = unexpected condition value `{$value}` for condition name `{$name}`
- .help = was set with `--cfg` but isn't in the `--check-cfg` expected values
-
-lint_builtin_type_alias_bounds_help = use fully disambiguated paths (i.e., `<T as Trait>::Assoc`) to refer to associated types in type aliases
-
-lint_builtin_type_alias_where_clause = where clauses are not enforced in type aliases
- .suggestion = the clause will not be checked when the type alias is used, and should be removed
-
-lint_builtin_type_alias_generic_bounds = bounds on generic parameters are not enforced in type aliases
- .suggestion = the bound will not be checked when the type alias is used, and should be removed
-
-lint_builtin_trivial_bounds = {$predicate_kind_name} bound {$predicate} does not depend on any type or lifetime parameters
-
-lint_builtin_ellipsis_inclusive_range_patterns = `...` range patterns are deprecated
- .suggestion = use `..=` for an inclusive range
-
-lint_builtin_unnameable_test_items = cannot test inner items
-
-lint_builtin_keyword_idents = `{$kw}` is a keyword in the {$next} edition
- .suggestion = you can use a raw identifier to stay compatible
-
-lint_builtin_explicit_outlives = outlives requirements can be inferred
- .suggestion = remove {$count ->
- [one] this bound
- *[other] these bounds
- }
-
-lint_builtin_incomplete_features = the feature `{$name}` is incomplete and may not be safe to use and/or cause compiler crashes
- .note = see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
- .help = consider using `min_{$name}` instead, which is more stable and complete
-
-lint_builtin_unpermitted_type_init_zeroed = the type `{$ty}` does not permit zero-initialization
-lint_builtin_unpermitted_type_init_unint = the type `{$ty}` does not permit being left uninitialized
-
-lint_builtin_unpermitted_type_init_label = this code causes undefined behavior when executed
-lint_builtin_unpermitted_type_init_label_suggestion = help: use `MaybeUninit<T>` instead, and only call `assume_init` after initialization is done
-
-lint_builtin_clashing_extern_same_name = `{$this}` redeclared with a different signature
- .previous_decl_label = `{$orig}` previously declared here
- .mismatch_label = this signature doesn't match the previous declaration
-lint_builtin_clashing_extern_diff_name = `{$this}` redeclares `{$orig}` with a different signature
- .previous_decl_label = `{$orig}` previously declared here
- .mismatch_label = this signature doesn't match the previous declaration
-
-lint_builtin_deref_nullptr = dereferencing a null pointer
- .label = this code causes undefined behavior when executed
-
-lint_builtin_asm_labels = avoid using named labels in inline assembly
-
-lint_builtin_special_module_name_used_lib = found module declaration for lib.rs
- .note = lib.rs is the root of this crate's library target
- .help = to refer to it from other targets, use the library's name as the path
-
-lint_builtin_special_module_name_used_main = found module declaration for main.rs
- .note = a binary crate cannot be used as library
-
-lint_supertrait_as_deref_target = `{$t}` implements `Deref` with supertrait `{$target_principal}` as target
- .label = target type is set here
-
-lint_overruled_attribute = {$lint_level}({$lint_source}) incompatible with previous forbid
- .label = overruled by previous forbid
-
-lint_default_source = `forbid` lint level is the default for {$id}
-
-lint_node_source = `forbid` level set here
- .note = {$reason}
-
-lint_command_line_source = `forbid` lint level was set on command line
-
-lint_malformed_attribute = malformed lint attribute input
-
-lint_bad_attribute_argument = bad attribute argument
-
-lint_reason_must_be_string_literal = reason must be a string literal
-
-lint_reason_must_come_last = reason in lint attribute must come last
-
-lint_unknown_tool_in_scoped_lint = unknown tool name `{$tool_name}` found in scoped lint: `{$tool_name}::{$lint_name}`
- .help = add `#![register_tool({$tool_name})]` to the crate root
-
-lint_unsupported_group = `{$lint_group}` lint group is not supported with ´--force-warn´
-
-lint_requested_level = requested on the command line with `{$level} {$lint_name}`
-
-lint_check_name_unknown = unknown lint: `{$lint_name}`
- .help = did you mean: `{$suggestion}`
-
-lint_check_name_unknown_tool = unknown lint tool: `{$tool_name}`
+lint_unused_generator =
+ unused {$pre}{$count ->
+ [one] generator
+ *[other] generator
+ }{$post} that must be used
+ .note = generators are lazy and do nothing unless resumed
-lint_check_name_warning = {$msg}
+lint_unused_import_braces = braces around {$node} is unnecessary
-lint_check_name_deprecated = lint name `{$lint_name}` is deprecated and does not have an effect anymore. Use: {$new_name}
+lint_unused_op = unused {$op} that must be used
+ .label = the {$op} produces a value
+ .suggestion = use `let _ = ...` to ignore the resulting value
-lint_opaque_hidden_inferred_bound = opaque type `{$ty}` does not satisfy its associated type bounds
- .specifically = this associated type bound is unsatisfied for `{$proj_ty}`
+lint_unused_result = unused result of type `{$ty}`
-lint_opaque_hidden_inferred_bound_sugg = add this bound
+lint_variant_size_differences =
+ enum variant is more than three times larger ({$largest} bytes) than the next largest
diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs
index 6b387df78..85141836e 100644
--- a/compiler/rustc_lint/src/builtin.rs
+++ b/compiler/rustc_lint/src/builtin.rs
@@ -22,7 +22,7 @@
use crate::fluent_generated as fluent;
use crate::{
- errors::BuiltinEllpisisInclusiveRangePatterns,
+ errors::BuiltinEllipsisInclusiveRangePatterns,
lints::{
BuiltinAnonymousParams, BuiltinBoxPointers, BuiltinClashingExtern,
BuiltinClashingExternSub, BuiltinConstNoMangle, BuiltinDeprecatedAttrLink,
@@ -62,7 +62,9 @@ use rustc_middle::lint::in_external_macro;
use rustc_middle::ty::layout::{LayoutError, LayoutOf};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::subst::GenericArgKind;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Instance, Ty, TyCtxt, VariantDef};
+use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, FutureIncompatibilityReason};
use rustc_span::edition::Edition;
use rustc_span::source_map::Spanned;
@@ -116,8 +118,7 @@ impl EarlyLintPass for WhileTrue {
#[inline]
fn check_expr(&mut self, cx: &EarlyContext<'_>, e: &ast::Expr) {
if let ast::ExprKind::While(cond, _, label) = &e.kind
- && let cond = pierce_parens(cond)
- && let ast::ExprKind::Lit(token_lit) = cond.kind
+ && let ast::ExprKind::Lit(token_lit) = pierce_parens(cond).kind
&& let token::Lit { kind: token::Bool, symbol: kw::True, .. } = token_lit
&& !cond.span.from_expansion()
{
@@ -166,10 +167,8 @@ declare_lint_pass!(BoxPointers => [BOX_POINTERS]);
impl BoxPointers {
fn check_heap_type(&self, cx: &LateContext<'_>, span: Span, ty: Ty<'_>) {
for leaf in ty.walk() {
- if let GenericArgKind::Type(leaf_ty) = leaf.unpack() {
- if leaf_ty.is_box() {
- cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
- }
+ if let GenericArgKind::Type(leaf_ty) = leaf.unpack() && leaf_ty.is_box() {
+ cx.emit_spanned_lint(BOX_POINTERS, span, BuiltinBoxPointers { ty });
}
}
}
@@ -548,32 +547,17 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
}
fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) {
- match it.kind {
- hir::ItemKind::Trait(..) => {
- // Issue #11592: traits are always considered exported, even when private.
- if cx.tcx.visibility(it.owner_id)
- == ty::Visibility::Restricted(
- cx.tcx.parent_module_from_def_id(it.owner_id.def_id).to_def_id(),
- )
- {
- return;
- }
- }
- hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::Macro(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::Enum(..)
- | hir::ItemKind::Struct(..)
- | hir::ItemKind::Union(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::Static(..) => {}
-
- _ => return,
- };
+ // Previously the Impl and Use types have been excluded from missing docs,
+ // so we will continue to exclude them for compatibility.
+ //
+ // The documentation on `ExternCrate` is not used at the moment so no need to warn for it.
+ if let hir::ItemKind::Impl(..) | hir::ItemKind::Use(..) | hir::ItemKind::ExternCrate(_) =
+ it.kind
+ {
+ return;
+ }
let (article, desc) = cx.tcx.article_and_description(it.owner_id.to_def_id());
-
self.check_missing_docs_attrs(cx, it.owner_id.def_id, article, desc);
}
@@ -631,7 +615,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc {
declare_lint! {
/// The `missing_copy_implementations` lint detects potentially-forgotten
- /// implementations of [`Copy`].
+ /// implementations of [`Copy`] for public types.
///
/// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html
///
@@ -667,7 +651,9 @@ declare_lint_pass!(MissingCopyImplementations => [MISSING_COPY_IMPLEMENTATIONS])
impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
+ if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
+ && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
+ {
return;
}
let (def, ty) = match item.kind {
@@ -747,7 +733,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations {
declare_lint! {
/// The `missing_debug_implementations` lint detects missing
- /// implementations of [`fmt::Debug`].
+ /// implementations of [`fmt::Debug`] for public types.
///
/// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html
///
@@ -786,7 +772,9 @@ impl_lint_pass!(MissingDebugImplementations => [MISSING_DEBUG_IMPLEMENTATIONS]);
impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations {
fn check_item(&mut self, cx: &LateContext<'_>, item: &hir::Item<'_>) {
- if !cx.effective_visibilities.is_reachable(item.owner_id.def_id) {
+ if !(cx.effective_visibilities.is_reachable(item.owner_id.def_id)
+ && cx.tcx.local_visibility(item.owner_id.def_id).is_public())
+ {
return;
}
@@ -977,7 +965,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: &
Some(sugared_span.map_or(attr.span, |span| span.with_hi(attr.span.hi())));
}
- if attrs.peek().map_or(false, |next_attr| next_attr.is_doc_comment()) {
+ if attrs.peek().is_some_and(|next_attr| next_attr.is_doc_comment()) {
continue;
}
@@ -1463,6 +1451,10 @@ impl<'tcx> LateLintPass<'tcx> for TypeAliasBounds {
// Bounds are respected for `type X = impl Trait`
return;
}
+ if cx.tcx.type_of(item.owner_id).skip_binder().has_inherent_projections() {
+ // Bounds are respected for `type X = … Type::Inherent …`
+ return;
+ }
// There must not be a where clause
if type_alias_generics.predicates.is_empty() {
return;
@@ -1582,7 +1574,6 @@ declare_lint_pass!(
impl<'tcx> LateLintPass<'tcx> for TrivialConstraints {
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
- use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::Clause;
use rustc_middle::ty::PredicateKind::*;
@@ -1711,13 +1702,13 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
}
}
- let (parenthesise, endpoints) = match &pat.kind {
+ let (parentheses, endpoints) = match &pat.kind {
PatKind::Ref(subpat, _) => (true, matches_ellipsis_pat(&subpat)),
_ => (false, matches_ellipsis_pat(pat)),
};
if let Some((start, end, join)) = endpoints {
- if parenthesise {
+ if parentheses {
self.node_id = Some(pat.id);
let end = expr_to_string(&end);
let replace = match start {
@@ -1725,7 +1716,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
None => format!("&(..={})", end),
};
if join.edition() >= Edition::Edition2021 {
- cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
span: pat.span,
suggestion: pat.span,
replace,
@@ -1743,7 +1734,7 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns {
} else {
let replace = "..=";
if join.edition() >= Edition::Edition2021 {
- cx.sess().emit_err(BuiltinEllpisisInclusiveRangePatterns {
+ cx.sess().emit_err(BuiltinEllipsisInclusiveRangePatterns {
span: pat.span,
suggestion: join,
replace: replace.to_string(),
@@ -1899,8 +1890,8 @@ declare_lint_pass!(
struct UnderMacro(bool);
impl KeywordIdents {
- fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: TokenStream) {
- for tt in tokens.into_trees() {
+ fn check_tokens(&mut self, cx: &EarlyContext<'_>, tokens: &TokenStream) {
+ for tt in tokens.trees() {
match tt {
// Only report non-raw idents.
TokenTree::Token(token, _) => {
@@ -1961,10 +1952,10 @@ impl KeywordIdents {
impl EarlyLintPass for KeywordIdents {
fn check_mac_def(&mut self, cx: &EarlyContext<'_>, mac_def: &ast::MacroDef) {
- self.check_tokens(cx, mac_def.body.tokens.clone());
+ self.check_tokens(cx, &mac_def.body.tokens);
}
fn check_mac(&mut self, cx: &EarlyContext<'_>, mac: &ast::MacCall) {
- self.check_tokens(cx, mac.args.tokens.clone());
+ self.check_tokens(cx, &mac.args.tokens);
}
fn check_ident(&mut self, cx: &EarlyContext<'_>, ident: Ident) {
self.check_ident_token(cx, UnderMacro(false), ident);
@@ -2560,7 +2551,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
.subst(cx.tcx, substs)
.apply_any_module(cx.tcx, cx.param_env)
{
- // Entirely skip uninhbaited variants.
+ // Entirely skip uninhabited variants.
Some(false) => return None,
// Forward the others, but remember which ones are definitely inhabited.
Some(true) => true,
@@ -2628,7 +2619,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue {
if let Some(err) = with_no_trimmed_paths!(ty_find_init_error(cx, conjured_ty, init)) {
let msg = match init {
InitKind::Zeroed => fluent::lint_builtin_unpermitted_type_init_zeroed,
- InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_unint,
+ InitKind::Uninit => fluent::lint_builtin_unpermitted_type_init_uninit,
};
let sub = BuiltinUnpermittedTypeInitSub { err };
cx.emit_spanned_lint(
@@ -2919,6 +2910,7 @@ impl ClashingExternDeclarations {
| (Generator(..), Generator(..))
| (GeneratorWitness(..), GeneratorWitness(..))
| (Alias(ty::Projection, ..), Alias(ty::Projection, ..))
+ | (Alias(ty::Inherent, ..), Alias(ty::Inherent, ..))
| (Alias(ty::Opaque, ..), Alias(ty::Opaque, ..)) => false,
// These definitely should have been caught above.
@@ -3308,16 +3300,15 @@ impl EarlyLintPass for UnexpectedCfgs {
let cfg = &cx.sess().parse_sess.config;
let check_cfg = &cx.sess().parse_sess.check_config;
for &(name, value) in cfg {
- if let Some(names_valid) = &check_cfg.names_valid && !names_valid.contains(&name){
- cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName {
- name,
- });
- }
- if let Some(value) = value && let Some(values) = check_cfg.values_valid.get(&name) && !values.contains(&value) {
- cx.emit_lint(
- UNEXPECTED_CFGS,
- BuiltinUnexpectedCliConfigValue { name, value },
- );
+ match check_cfg.expecteds.get(&name) {
+ Some(ExpectedValues::Some(values)) if !values.contains(&value) => {
+ let value = value.unwrap_or(kw::Empty);
+ cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigValue { name, value });
+ }
+ None if check_cfg.exhaustive_names => {
+ cx.emit_lint(UNEXPECTED_CFGS, BuiltinUnexpectedCliConfigName { name });
+ }
+ _ => { /* expected */ }
}
}
}
diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs
index 626c09fea..1d0c43e95 100644
--- a/compiler/rustc_lint/src/context.rs
+++ b/compiler/rustc_lint/src/context.rs
@@ -36,6 +36,7 @@ use rustc_middle::middle::stability;
use rustc_middle::ty::layout::{LayoutError, LayoutOfHelpers, TyAndLayout};
use rustc_middle::ty::print::with_no_trimmed_paths;
use rustc_middle::ty::{self, print::Printer, subst::GenericArg, RegisteredTools, Ty, TyCtxt};
+use rustc_session::config::ExpectedValues;
use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId};
use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId};
use rustc_session::Session;
@@ -48,9 +49,9 @@ use std::cell::Cell;
use std::iter;
use std::slice;
-type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::Send + sync::Sync;
+type EarlyLintPassFactory = dyn Fn() -> EarlyLintPassObject + sync::DynSend + sync::DynSync;
type LateLintPassFactory =
- dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::Send + sync::Sync;
+ dyn for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx> + sync::DynSend + sync::DynSync;
/// Information about the registered lints.
///
@@ -168,7 +169,7 @@ impl LintStore {
pub fn register_early_pass(
&mut self,
- pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+ pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.early_passes.push(Box::new(pass));
}
@@ -181,7 +182,7 @@ impl LintStore {
/// * See [rust-clippy#5518](https://github.com/rust-lang/rust-clippy/pull/5518)
pub fn register_pre_expansion_pass(
&mut self,
- pass: impl Fn() -> EarlyLintPassObject + 'static + sync::Send + sync::Sync,
+ pass: impl Fn() -> EarlyLintPassObject + 'static + sync::DynSend + sync::DynSync,
) {
self.pre_expansion_passes.push(Box::new(pass));
}
@@ -190,8 +191,8 @@ impl LintStore {
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
- + sync::Send
- + sync::Sync,
+ + sync::DynSend
+ + sync::DynSync,
) {
self.late_passes.push(Box::new(pass));
}
@@ -200,8 +201,8 @@ impl LintStore {
&mut self,
pass: impl for<'tcx> Fn(TyCtxt<'tcx>) -> LateLintPassObject<'tcx>
+ 'static
- + sync::Send
- + sync::Sync,
+ + sync::DynSend
+ + sync::DynSync,
) {
self.late_module_passes.push(Box::new(pass));
}
@@ -616,7 +617,7 @@ pub trait LintContext: Sized {
1 => ("an ", ""),
_ => ("", "s"),
};
- db.span_label(span, &format!(
+ db.span_label(span, format!(
"this comment contains {}invisible unicode text flow control codepoint{}",
an,
s,
@@ -680,12 +681,12 @@ pub trait LintContext: Sized {
);
}
BuiltinLintDiagnostics::UnknownCrateTypes(span, note, sugg) => {
- db.span_suggestion(span, &note, sugg, Applicability::MaybeIncorrect);
+ db.span_suggestion(span, note, sugg, Applicability::MaybeIncorrect);
}
BuiltinLintDiagnostics::UnusedImports(message, replaces, in_test_module) => {
if !replaces.is_empty() {
db.tool_only_multipart_suggestion(
- &message,
+ message,
replaces,
Applicability::MachineApplicable,
);
@@ -720,13 +721,13 @@ pub trait LintContext: Sized {
}
BuiltinLintDiagnostics::MissingAbi(span, default_abi) => {
db.span_label(span, "ABI should be specified here");
- db.help(&format!("the default ABI is {}", default_abi.name()));
+ db.help(format!("the default ABI is {}", default_abi.name()));
}
BuiltinLintDiagnostics::LegacyDeriveHelpers(span) => {
db.span_label(span, "the attribute is introduced here");
}
BuiltinLintDiagnostics::ProcMacroBackCompat(note) => {
- db.note(&note);
+ db.note(note);
}
BuiltinLintDiagnostics::OrPatternsBackCompat(span,suggestion) => {
db.span_suggestion(span, "use pat_param to preserve semantics", suggestion, Applicability::MachineApplicable);
@@ -747,13 +748,13 @@ pub trait LintContext: Sized {
} => {
db.span_note(
invoc_span,
- &format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
+ format!("the built-in attribute `{attr_name}` will be ignored, since it's applied to the macro invocation `{macro_name}`")
);
}
BuiltinLintDiagnostics::TrailingMacro(is_trailing, name) => {
if is_trailing {
db.note("macro invocations at the end of a block are treated as expressions");
- db.note(&format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
+ db.note(format!("to ignore the value produced by the macro, add a semicolon after the invocation of `{name}`"));
}
}
BuiltinLintDiagnostics::BreakWithLabelAndLoop(span) => {
@@ -765,25 +766,55 @@ pub trait LintContext: Sized {
);
}
BuiltinLintDiagnostics::NamedAsmLabel(help) => {
- db.help(&help);
+ db.help(help);
db.note("see the asm section of Rust By Example <https://doc.rust-lang.org/nightly/rust-by-example/unsafe/asm.html#labels> for more information");
},
- BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), None) => {
- let Some(names_valid) = &sess.parse_sess.check_config.names_valid else {
- bug!("it shouldn't be possible to have a diagnostic on a name if name checking is not enabled");
- };
- let possibilities: Vec<Symbol> = names_valid.iter().map(|s| *s).collect();
+ BuiltinLintDiagnostics::UnexpectedCfgName((name, name_span), value) => {
+ let possibilities: Vec<Symbol> = sess.parse_sess.check_config.expecteds.keys().map(|s| *s).collect();
// Suggest the most probable if we found one
if let Some(best_match) = find_best_match_for_name(&possibilities, name, None) {
- db.span_suggestion(name_span, "did you mean", best_match, Applicability::MaybeIncorrect);
+ if let Some(ExpectedValues::Some(best_match_values)) =
+ sess.parse_sess.check_config.expecteds.get(&best_match) {
+ let mut possibilities = best_match_values.iter()
+ .flatten()
+ .map(Symbol::as_str)
+ .collect::<Vec<_>>();
+ possibilities.sort();
+
+ if let Some((value, value_span)) = value {
+ if best_match_values.contains(&Some(value)) {
+ db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect);
+ } else if best_match_values.contains(&None) {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect);
+ } else if let Some(first_value) = possibilities.first() {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect);
+ } else {
+ db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", best_match, Applicability::MaybeIncorrect);
+ };
+ } else {
+ db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+ }
+
+ if !possibilities.is_empty() {
+ let possibilities = possibilities.join("`, `");
+ db.help(format!("expected values for `{best_match}` are: `{possibilities}`"));
+ }
+ } else {
+ db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect);
+ }
}
},
- BuiltinLintDiagnostics::UnexpectedCfg((name, name_span), Some((value, value_span))) => {
- let Some(values) = &sess.parse_sess.check_config.values_valid.get(&name) else {
+ BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => {
+ let Some(ExpectedValues::Some(values)) = &sess.parse_sess.check_config.expecteds.get(&name) else {
bug!("it shouldn't be possible to have a diagnostic on a value whose name is not in values");
};
- let possibilities: Vec<Symbol> = values.iter().map(|&s| s).collect();
+ let mut have_none_possibility = false;
+ let possibilities: Vec<Symbol> = values.iter()
+ .inspect(|a| have_none_possibility |= a.is_none())
+ .copied()
+ .flatten()
+ .collect();
// Show the full list if all possible values for a given name, but don't do it
// for names as the possibilities could be very long
@@ -792,17 +823,24 @@ pub trait LintContext: Sized {
let mut possibilities = possibilities.iter().map(Symbol::as_str).collect::<Vec<_>>();
possibilities.sort();
- let possibilities = possibilities.join(", ");
- db.note(&format!("expected values for `{name}` are: {possibilities}"));
+ let possibilities = possibilities.join("`, `");
+ let none = if have_none_possibility { "(none), " } else { "" };
+
+ db.note(format!("expected values for `{name}` are: {none}`{possibilities}`"));
}
- // Suggest the most probable if we found one
- if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
- db.span_suggestion(value_span, "did you mean", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+ if let Some((value, value_span)) = value {
+ // Suggest the most probable if we found one
+ if let Some(best_match) = find_best_match_for_name(&possibilities, value, None) {
+ db.span_suggestion(value_span, "there is a expected value with a similar name", format!("\"{best_match}\""), Applicability::MaybeIncorrect);
+
+ }
+ } else if let &[first_possibility] = &possibilities[..] {
+ db.span_suggestion(name_span.shrink_to_hi(), "specify a config value", format!(" = \"{first_possibility}\""), Applicability::MaybeIncorrect);
}
- } else {
- db.note(&format!("no expected value for `{name}`"));
- if name != sym::feature {
+ } else if have_none_possibility {
+ db.note(format!("no expected value for `{name}`"));
+ if let Some((_value, value_span)) = value {
db.span_suggestion(name_span.shrink_to_hi().to(value_span), "remove the value", "", Applicability::MaybeIncorrect);
}
}
diff --git a/compiler/rustc_lint/src/drop_forget_useless.rs b/compiler/rustc_lint/src/drop_forget_useless.rs
new file mode 100644
index 000000000..77e4a7669
--- /dev/null
+++ b/compiler/rustc_lint/src/drop_forget_useless.rs
@@ -0,0 +1,164 @@
+use rustc_hir::{Arm, Expr, ExprKind, Node};
+use rustc_span::sym;
+
+use crate::{
+ lints::{DropCopyDiag, DropRefDiag, ForgetCopyDiag, ForgetRefDiag},
+ LateContext, LateLintPass, LintContext,
+};
+
+declare_lint! {
+ /// The `dropping_references` lint checks for calls to `std::mem::drop` with a reference
+ /// instead of an owned value.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # fn operation_that_requires_mutex_to_be_unlocked() {} // just to make it compile
+ /// # let mutex = std::sync::Mutex::new(1); // just to make it compile
+ /// let mut lock_guard = mutex.lock();
+ /// std::mem::drop(&lock_guard); // Should have been drop(lock_guard), mutex
+ /// // still locked
+ /// operation_that_requires_mutex_to_be_unlocked();
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `drop` on a reference will only drop the
+ /// reference itself, which is a no-op. It will not call the `drop` method (from
+ /// the `Drop` trait implementation) on the underlying referenced value, which
+ /// is likely what was intended.
+ pub DROPPING_REFERENCES,
+ Warn,
+ "calls to `std::mem::drop` with a reference instead of an owned value"
+}
+
+declare_lint! {
+ /// The `forgetting_references` lint checks for calls to `std::mem::forget` with a reference
+ /// instead of an owned value.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x = Box::new(1);
+ /// std::mem::forget(&x); // Should have been forget(x), x will still be dropped
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `forget` on a reference will only forget the
+ /// reference itself, which is a no-op. It will not forget the underlying
+ /// referenced value, which is likely what was intended.
+ pub FORGETTING_REFERENCES,
+ Warn,
+ "calls to `std::mem::forget` with a reference instead of an owned value"
+}
+
+declare_lint! {
+ /// The `dropping_copy_types` lint checks for calls to `std::mem::drop` with a value
+ /// that derives the Copy trait.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x: i32 = 42; // i32 implements Copy
+ /// std::mem::drop(x); // A copy of x is passed to the function, leaving the
+ /// // original unaffected
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `std::mem::drop` [does nothing for types that
+ /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html), since the
+ /// value will be copied and moved into the function on invocation.
+ pub DROPPING_COPY_TYPES,
+ Warn,
+ "calls to `std::mem::drop` with a value that implements Copy"
+}
+
+declare_lint! {
+ /// The `forgetting_copy_types` lint checks for calls to `std::mem::forget` with a value
+ /// that derives the Copy trait.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// let x: i32 = 42; // i32 implements Copy
+ /// std::mem::forget(x); // A copy of x is passed to the function, leaving the
+ /// // original unaffected
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Calling `std::mem::forget` [does nothing for types that
+ /// implement Copy](https://doc.rust-lang.org/std/mem/fn.drop.html) since the
+ /// value will be copied and moved into the function on invocation.
+ ///
+ /// An alternative, but also valid, explanation is that Copy types do not
+ /// implement the Drop trait, which means they have no destructors. Without a
+ /// destructor, there is nothing for `std::mem::forget` to ignore.
+ pub FORGETTING_COPY_TYPES,
+ Warn,
+ "calls to `std::mem::forget` with a value that implements Copy"
+}
+
+declare_lint_pass!(DropForgetUseless => [DROPPING_REFERENCES, FORGETTING_REFERENCES, DROPPING_COPY_TYPES, FORGETTING_COPY_TYPES]);
+
+impl<'tcx> LateLintPass<'tcx> for DropForgetUseless {
+ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
+ if let ExprKind::Call(path, [arg]) = expr.kind
+ && let ExprKind::Path(ref qpath) = path.kind
+ && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
+ && let Some(fn_name) = cx.tcx.get_diagnostic_name(def_id)
+ {
+ let arg_ty = cx.typeck_results().expr_ty(arg);
+ let is_copy = arg_ty.is_copy_modulo_regions(cx.tcx, cx.param_env);
+ let drop_is_single_call_in_arm = is_single_call_in_arm(cx, arg, expr);
+ match fn_name {
+ sym::mem_drop if arg_ty.is_ref() && !drop_is_single_call_in_arm => {
+ cx.emit_spanned_lint(DROPPING_REFERENCES, expr.span, DropRefDiag { arg_ty, label: arg.span });
+ },
+ sym::mem_forget if arg_ty.is_ref() => {
+ cx.emit_spanned_lint(FORGETTING_REFERENCES, expr.span, ForgetRefDiag { arg_ty, label: arg.span });
+ },
+ sym::mem_drop if is_copy && !drop_is_single_call_in_arm => {
+ cx.emit_spanned_lint(DROPPING_COPY_TYPES, expr.span, DropCopyDiag { arg_ty, label: arg.span });
+ }
+ sym::mem_forget if is_copy => {
+ cx.emit_spanned_lint(FORGETTING_COPY_TYPES, expr.span, ForgetCopyDiag { arg_ty, label: arg.span });
+ }
+ _ => return,
+ };
+ }
+ }
+}
+
+// Dropping returned value of a function, as in the following snippet is considered idiomatic, see
+// rust-lang/rust-clippy#9482 for examples.
+//
+// ```
+// match <var> {
+// <pat> => drop(fn_with_side_effect_and_returning_some_value()),
+// ..
+// }
+// ```
+fn is_single_call_in_arm<'tcx>(
+ cx: &LateContext<'tcx>,
+ arg: &'tcx Expr<'_>,
+ drop_expr: &'tcx Expr<'_>,
+) -> bool {
+ if arg.can_have_side_effects() {
+ let parent_node = cx.tcx.hir().find_parent(drop_expr.hir_id);
+ if let Some(Node::Arm(Arm { body, .. })) = &parent_node {
+ return body.hir_id == drop_expr.hir_id;
+ }
+ }
+ false
+}
diff --git a/compiler/rustc_lint/src/early.rs b/compiler/rustc_lint/src/early.rs
index 65607d718..9f1f5a26e 100644
--- a/compiler/rustc_lint/src/early.rs
+++ b/compiler/rustc_lint/src/early.rs
@@ -428,7 +428,7 @@ pub fn check_ast_node_inner<'a, T: EarlyLintPass>(
for early_lint in lints {
sess.delay_span_bug(
early_lint.span,
- &format!(
+ format!(
"failed to process buffered lint here (dummy = {})",
id == ast::DUMMY_NODE_ID
),
diff --git a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
index f1ba192f2..2ce28f3a0 100644
--- a/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
+++ b/compiler/rustc_lint/src/enum_intrinsics_non_enums.rs
@@ -42,7 +42,7 @@ declare_lint_pass!(EnumIntrinsicsNonEnums => [ENUM_INTRINSICS_NON_ENUMS]);
/// Returns `true` if we know for sure that the given type is not an enum. Note that for cases where
/// the type is generic, we can't be certain if it will be an enum so we have to assume that it is.
fn is_non_enum(t: Ty<'_>) -> bool {
- !t.is_enum() && !t.needs_subst()
+ !t.is_enum() && !t.has_param()
}
fn enforce_mem_discriminant(
diff --git a/compiler/rustc_lint/src/errors.rs b/compiler/rustc_lint/src/errors.rs
index 9af5284df..bbae3d368 100644
--- a/compiler/rustc_lint/src/errors.rs
+++ b/compiler/rustc_lint/src/errors.rs
@@ -81,7 +81,7 @@ pub struct UnknownToolInScopedLint {
#[derive(Diagnostic)]
#[diag(lint_builtin_ellipsis_inclusive_range_patterns, code = "E0783")]
-pub struct BuiltinEllpisisInclusiveRangePatterns {
+pub struct BuiltinEllipsisInclusiveRangePatterns {
#[primary_span]
pub span: Span,
#[suggestion(style = "short", code = "{replace}", applicability = "machine-applicable")]
diff --git a/compiler/rustc_lint/src/expect.rs b/compiler/rustc_lint/src/expect.rs
index e9eb14ea1..b1266b58a 100644
--- a/compiler/rustc_lint/src/expect.rs
+++ b/compiler/rustc_lint/src/expect.rs
@@ -1,5 +1,5 @@
use crate::lints::{Expectation, ExpectationNote};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNFULFILLED_LINT_EXPECTATIONS;
use rustc_session::lint::LintExpectationId;
diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs
index 4ac589c2e..6f773e04a 100644
--- a/compiler/rustc_lint/src/internal.rs
+++ b/compiler/rustc_lint/src/internal.rs
@@ -4,6 +4,7 @@
use crate::lints::{
BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, LintPassByHand, NonExistentDocKeyword,
QueryInstability, TyQualified, TykindDiag, TykindKind, UntranslatableDiag,
+ UntranslatableDiagnosticTrivial,
};
use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
use rustc_ast as ast;
@@ -366,7 +367,15 @@ declare_tool_lint! {
report_in_external_macro: true
}
-declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL ]);
+declare_tool_lint! {
+ /// The `untranslatable_diagnostic_trivial` lint detects diagnostics created using only static strings.
+ pub rustc::UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
+ Deny,
+ "prevent creation of diagnostics which cannot be translated, which use only static strings",
+ report_in_external_macro: true
+}
+
+declare_lint_pass!(Diagnostics => [ UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL, UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL ]);
impl LateLintPass<'_> for Diagnostics {
fn check_expr(&mut self, cx: &LateContext<'_>, expr: &Expr<'_>) {
@@ -374,9 +383,8 @@ impl LateLintPass<'_> for Diagnostics {
debug!(?span, ?def_id, ?substs);
let has_attr = ty::Instance::resolve(cx.tcx, cx.param_env, def_id, substs)
.ok()
- .and_then(|inst| inst)
- .map(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics))
- .unwrap_or(false);
+ .flatten()
+ .is_some_and(|inst| cx.tcx.has_attr(inst.def_id(), sym::rustc_lint_diagnostics));
if !has_attr {
return;
}
@@ -423,6 +431,77 @@ impl LateLintPass<'_> for Diagnostics {
}
}
+impl EarlyLintPass for Diagnostics {
+ #[allow(unused_must_use)]
+ fn check_stmt(&mut self, cx: &EarlyContext<'_>, stmt: &ast::Stmt) {
+ // Looking for a straight chain of method calls from 'struct_span_err' to 'emit'.
+ let ast::StmtKind::Semi(expr) = &stmt.kind else {
+ return;
+ };
+ let ast::ExprKind::MethodCall(meth) = &expr.kind else {
+ return;
+ };
+ if meth.seg.ident.name != sym::emit || !meth.args.is_empty() {
+ return;
+ }
+ let mut segments = vec![];
+ let mut cur = &meth.receiver;
+ let fake = &[].into();
+ loop {
+ match &cur.kind {
+ ast::ExprKind::Call(func, args) => {
+ if let ast::ExprKind::Path(_, path) = &func.kind {
+ segments.push((path.segments.last().unwrap().ident.name, args))
+ }
+ break;
+ }
+ ast::ExprKind::MethodCall(method) => {
+ segments.push((method.seg.ident.name, &method.args));
+ cur = &method.receiver;
+ }
+ ast::ExprKind::MacCall(mac) => {
+ segments.push((mac.path.segments.last().unwrap().ident.name, fake));
+ break;
+ }
+ _ => {
+ break;
+ }
+ }
+ }
+ segments.reverse();
+ if segments.is_empty() {
+ return;
+ }
+ if segments[0].0.as_str() != "struct_span_err" {
+ return;
+ }
+ if !segments.iter().all(|(name, args)| {
+ let arg = match name.as_str() {
+ "struct_span_err" | "span_note" | "span_label" | "span_help" if args.len() == 2 => {
+ &args[1]
+ }
+ "note" | "help" if args.len() == 1 => &args[0],
+ _ => {
+ return false;
+ }
+ };
+ if let ast::ExprKind::Lit(lit) = arg.kind
+ && let ast::token::LitKind::Str = lit.kind {
+ true
+ } else {
+ false
+ }
+ }) {
+ return;
+ }
+ cx.emit_spanned_lint(
+ UNTRANSLATABLE_DIAGNOSTIC_TRIVIAL,
+ stmt.span,
+ UntranslatableDiagnosticTrivial,
+ );
+ }
+}
+
declare_tool_lint! {
/// The `bad_opt_access` lint detects accessing options by field instead of
/// the wrapper function.
diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs
index b42878a02..8a4a451f8 100644
--- a/compiler/rustc_lint/src/late.rs
+++ b/compiler/rustc_lint/src/late.rs
@@ -16,7 +16,7 @@
use crate::{passes::LateLintPassObject, LateContext, LateLintPass, LintStore};
use rustc_ast as ast;
-use rustc_data_structures::sync::join;
+use rustc_data_structures::sync::{join, DynSend};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit as hir_visit;
@@ -240,8 +240,10 @@ impl<'tcx, T: LateLintPass<'tcx>> hir_visit::Visitor<'tcx> for LateContextAndPas
}
fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) {
- lint_callback!(self, check_arm, a);
- hir_visit::walk_arm(self, a);
+ self.with_lint_attrs(a.hir_id, |cx| {
+ lint_callback!(cx, check_arm, a);
+ hir_visit::walk_arm(cx, a);
+ })
}
fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) {
@@ -429,7 +431,7 @@ fn late_lint_crate_inner<'tcx, T: LateLintPass<'tcx>>(
/// Performs lint checking on a crate.
pub fn check_crate<'tcx, T: LateLintPass<'tcx> + 'tcx>(
tcx: TyCtxt<'tcx>,
- builtin_lints: impl FnOnce() -> T + Send,
+ builtin_lints: impl FnOnce() -> T + Send + DynSend,
) {
join(
|| {
diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs
index bb863f095..8376835f5 100644
--- a/compiler/rustc_lint/src/levels.rs
+++ b/compiler/rustc_lint/src/levels.rs
@@ -14,13 +14,13 @@ use rustc_errors::{DecorateLint, DiagnosticBuilder, DiagnosticMessage, MultiSpan
use rustc_hir as hir;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::HirId;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::hir::nested_filter;
use rustc_middle::lint::{
reveal_actual_level, struct_lint_level, LevelAndSource, LintExpectation, LintLevelSource,
ShallowLintLevelMap,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{RegisteredTools, TyCtxt};
use rustc_session::lint::builtin::{RENAMED_AND_REMOVED_LINTS, UNKNOWN_LINTS, UNUSED_ATTRIBUTES};
use rustc_session::lint::{
@@ -242,7 +242,9 @@ impl LintLevelsProvider for LintLevelQueryMap<'_> {
struct QueryMapExpectationsWrapper<'tcx> {
tcx: TyCtxt<'tcx>,
+ /// HirId of the currently investigated element.
cur: HirId,
+ /// Level map for `cur`.
specs: ShallowLintLevelMap,
expectations: Vec<(LintExpectationId, LintExpectation)>,
unstable_to_stable_ids: FxHashMap<LintExpectationId, LintExpectationId>,
@@ -255,11 +257,11 @@ impl LintLevelsProvider for QueryMapExpectationsWrapper<'_> {
self.specs.specs.get(&self.cur.local_id).unwrap_or(&self.empty)
}
fn insert(&mut self, id: LintId, lvl: LevelAndSource) {
- let specs = self.specs.specs.get_mut_or_insert_default(self.cur.local_id);
- specs.clear();
- specs.insert(id, lvl);
+ self.specs.specs.get_mut_or_insert_default(self.cur.local_id).insert(id, lvl);
}
fn get_lint_level(&self, lint: &'static Lint, _: &Session) -> LevelAndSource {
+ // We cannot use `tcx.lint_level_at_node` because we want to know in which order the
+ // attributes have been inserted, in particular whether an `expect` follows a `forbid`.
self.specs.lint_level_id_at_node(self.tcx, LintId::of(lint), self.cur)
}
fn push_expectation(&mut self, id: LintExpectationId, expectation: LintExpectation) {
@@ -355,7 +357,9 @@ impl<'tcx> Visitor<'tcx> for LintLevelsBuilder<'_, LintLevelQueryMap<'tcx>> {
impl<'tcx> LintLevelsBuilder<'_, QueryMapExpectationsWrapper<'tcx>> {
fn add_id(&mut self, hir_id: HirId) {
+ // Change both the `HirId` and the associated specs.
self.provider.cur = hir_id;
+ self.provider.specs.specs.clear();
self.add(self.provider.tcx.hir().attrs(hir_id), hir_id == hir::CRATE_HIR_ID, Some(hir_id));
}
}
diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs
index b35785405..dfddfe09a 100644
--- a/compiler/rustc_lint/src/lib.rs
+++ b/compiler/rustc_lint/src/lib.rs
@@ -52,6 +52,7 @@ mod array_into_iter;
pub mod builtin;
mod context;
mod deref_into_dyn_supertrait;
+mod drop_forget_useless;
mod early;
mod enum_intrinsics_non_enums;
mod errors;
@@ -82,10 +83,10 @@ pub use array_into_iter::ARRAY_INTO_ITER;
use rustc_ast as ast;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
-use rustc_macros::fluent_messages;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::{
BARE_TRAIT_OBJECTS, ELIDED_LIFETIMES_IN_PATHS, EXPLICIT_OUTLIVES_REQUIREMENTS,
@@ -96,6 +97,7 @@ use rustc_span::Span;
use array_into_iter::ArrayIntoIter;
use builtin::*;
use deref_into_dyn_supertrait::*;
+use drop_forget_useless::*;
use enum_intrinsics_non_enums::EnumIntrinsicsNonEnums;
use for_loops_over_fallibles::*;
use hidden_unicode_codepoints::*;
@@ -201,6 +203,7 @@ late_lint_methods!(
[
ForLoopsOverFallibles: ForLoopsOverFallibles,
DerefIntoDynSupertrait: DerefIntoDynSupertrait,
+ DropForgetUseless: DropForgetUseless,
HardwiredLints: HardwiredLints,
ImproperCTypesDeclarations: ImproperCTypesDeclarations,
ImproperCTypesDefinitions: ImproperCTypesDefinitions,
@@ -518,6 +521,7 @@ fn register_internals(store: &mut LintStore) {
store.register_lints(&TyTyKind::get_lints());
store.register_late_pass(|_| Box::new(TyTyKind));
store.register_lints(&Diagnostics::get_lints());
+ store.register_early_pass(|| Box::new(Diagnostics));
store.register_late_pass(|_| Box::new(Diagnostics));
store.register_lints(&BadOptAccess::get_lints());
store.register_late_pass(|_| Box::new(BadOptAccess));
diff --git a/compiler/rustc_lint/src/lints.rs b/compiler/rustc_lint/src/lints.rs
index 1d5e02369..d96723a68 100644
--- a/compiler/rustc_lint/src/lints.rs
+++ b/compiler/rustc_lint/src/lints.rs
@@ -662,6 +662,43 @@ pub struct ForLoopsOverFalliblesSuggestion<'a> {
pub end_span: Span,
}
+// drop_forget_useless.rs
+#[derive(LintDiagnostic)]
+#[diag(lint_dropping_references)]
+#[note]
+pub struct DropRefDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_dropping_copy_types)]
+#[note]
+pub struct DropCopyDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_forgetting_references)]
+#[note]
+pub struct ForgetRefDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_forgetting_copy_types)]
+#[note]
+pub struct ForgetCopyDiag<'a> {
+ pub arg_ty: Ty<'a>,
+ #[label]
+ pub label: Span,
+}
+
// hidden_unicode_codepoints.rs
#[derive(LintDiagnostic)]
#[diag(lint_hidden_unicode_codepoints)]
@@ -821,6 +858,10 @@ pub struct DiagOutOfImpl;
pub struct UntranslatableDiag;
#[derive(LintDiagnostic)]
+#[diag(lint_trivial_untranslatable_diag)]
+pub struct UntranslatableDiagnosticTrivial;
+
+#[derive(LintDiagnostic)]
#[diag(lint_bad_opt_access)]
pub struct BadOptAccessDiag<'a> {
pub msg: &'a str,
@@ -1146,6 +1187,18 @@ pub struct NoopMethodCallDiag<'a> {
pub label: Span,
}
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_deref)]
+pub struct SuspiciousDoubleRefDerefDiag<'a> {
+ pub ty: Ty<'a>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(lint_suspicious_double_ref_clone)]
+pub struct SuspiciousDoubleRefCloneDiag<'a> {
+ pub ty: Ty<'a>,
+}
+
// pass_by_value.rs
#[derive(LintDiagnostic)]
#[diag(lint_pass_by_value)]
diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs
index 5bb1abfd2..b218cc578 100644
--- a/compiler/rustc_lint/src/non_fmt_panic.rs
+++ b/compiler/rustc_lint/src/non_fmt_panic.rs
@@ -128,7 +128,7 @@ fn check_panic<'tcx>(cx: &LateContext<'tcx>, f: &'tcx hir::Expr<'tcx>, arg: &'tc
// No clue where this argument is coming from.
return lint;
}
- if arg_macro.map_or(false, |id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
+ if arg_macro.is_some_and(|id| cx.tcx.is_diagnostic_item(sym::format_macro, id)) {
// A case of `panic!(format!(..))`.
lint.note(fluent::lint_supports_fmt_note);
if let Some((open, close, _)) = find_delimiters(cx, arg_span) {
diff --git a/compiler/rustc_lint/src/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs
index 9efc14849..79253cbc8 100644
--- a/compiler/rustc_lint/src/nonstandard_style.rs
+++ b/compiler/rustc_lint/src/nonstandard_style.rs
@@ -33,6 +33,11 @@ pub fn method_context(cx: &LateContext<'_>, id: LocalDefId) -> MethodLateContext
}
}
+fn assoc_item_in_trait_impl(cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) -> bool {
+ let item = cx.tcx.associated_item(ii.owner_id);
+ item.trait_item_def_id.is_some()
+}
+
declare_lint! {
/// The `non_camel_case_types` lint detects types, variants, traits and
/// type parameters that don't have camel case names.
@@ -177,6 +182,7 @@ impl EarlyLintPass for NonCamelCaseTypes {
// trait impls where we should have warned for the trait definition already.
ast::ItemKind::Impl(box ast::Impl { of_trait: None, items, .. }) => {
for it in items {
+ // FIXME: this doesn't respect `#[allow(..)]` on the item itself.
if let ast::AssocItemKind::Type(..) = it.kind {
self.check_case(cx, "associated type", &it.ident);
}
@@ -505,7 +511,7 @@ impl<'tcx> LateLintPass<'tcx> for NonUpperCaseGlobals {
}
fn check_impl_item(&mut self, cx: &LateContext<'_>, ii: &hir::ImplItem<'_>) {
- if let hir::ImplItemKind::Const(..) = ii.kind {
+ if let hir::ImplItemKind::Const(..) = ii.kind && !assoc_item_in_trait_impl(cx, ii) {
NonUpperCaseGlobals::check_upper_case(cx, "associated constant", &ii.ident);
}
}
diff --git a/compiler/rustc_lint/src/noop_method_call.rs b/compiler/rustc_lint/src/noop_method_call.rs
index d67a00619..d56c35bb6 100644
--- a/compiler/rustc_lint/src/noop_method_call.rs
+++ b/compiler/rustc_lint/src/noop_method_call.rs
@@ -1,10 +1,13 @@
use crate::context::LintContext;
-use crate::lints::NoopMethodCallDiag;
+use crate::lints::{
+ NoopMethodCallDiag, SuspiciousDoubleRefCloneDiag, SuspiciousDoubleRefDerefDiag,
+};
use crate::LateContext;
use crate::LateLintPass;
use rustc_hir::def::DefKind;
use rustc_hir::{Expr, ExprKind};
use rustc_middle::ty;
+use rustc_middle::ty::adjustment::Adjust;
use rustc_span::symbol::sym;
declare_lint! {
@@ -35,32 +38,62 @@ declare_lint! {
"detects the use of well-known noop methods"
}
-declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL]);
+declare_lint! {
+ /// The `suspicious_double_ref_op` lint checks for usage of `.clone()`/`.borrow()`/`.deref()`
+ /// on an `&&T` when `T: !Deref/Borrow/Clone`, which means the call will return the inner `&T`,
+ /// instead of performing the operation on the underlying `T` and can be confusing.
+ ///
+ /// ### Example
+ ///
+ /// ```rust
+ /// # #![allow(unused)]
+ /// struct Foo;
+ /// let foo = &&Foo;
+ /// let clone: &Foo = foo.clone();
+ /// ```
+ ///
+ /// {{produces}}
+ ///
+ /// ### Explanation
+ ///
+ /// Since `Foo` doesn't implement `Clone`, running `.clone()` only dereferences the double
+ /// reference, instead of cloning the inner type which should be what was intended.
+ pub SUSPICIOUS_DOUBLE_REF_OP,
+ Warn,
+ "suspicious call of trait method on `&&T`"
+}
+
+declare_lint_pass!(NoopMethodCall => [NOOP_METHOD_CALL, SUSPICIOUS_DOUBLE_REF_OP]);
impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) {
// We only care about method calls.
- let ExprKind::MethodCall(call, receiver, ..) = &expr.kind else {
- return
+ let ExprKind::MethodCall(call, receiver, _, call_span) = &expr.kind else {
+ return;
};
+
+ if call_span.from_expansion() {
+ return;
+ }
+
// We only care about method calls corresponding to the `Clone`, `Deref` and `Borrow`
// traits and ignore any other method call.
- let did = match cx.typeck_results().type_dependent_def(expr.hir_id) {
- // Verify we are dealing with a method/associated function.
- Some((DefKind::AssocFn, did)) => match cx.tcx.trait_of_item(did) {
- // Check that we're dealing with a trait method for one of the traits we care about.
- Some(trait_id)
- if matches!(
- cx.tcx.get_diagnostic_name(trait_id),
- Some(sym::Borrow | sym::Clone | sym::Deref)
- ) =>
- {
- did
- }
- _ => return,
- },
- _ => return,
+
+ let Some((DefKind::AssocFn, did)) =
+ cx.typeck_results().type_dependent_def(expr.hir_id)
+ else {
+ return;
};
+
+ let Some(trait_id) = cx.tcx.trait_of_item(did) else { return };
+
+ if !matches!(
+ cx.tcx.get_diagnostic_name(trait_id),
+ Some(sym::Borrow | sym::Clone | sym::Deref)
+ ) {
+ return;
+ };
+
let substs = cx
.tcx
.normalize_erasing_regions(cx.param_env, cx.typeck_results().node_substs(expr.hir_id));
@@ -70,25 +103,43 @@ impl<'tcx> LateLintPass<'tcx> for NoopMethodCall {
};
// (Re)check that it implements the noop diagnostic.
let Some(name) = cx.tcx.get_diagnostic_name(i.def_id()) else { return };
- if !matches!(
- name,
- sym::noop_method_borrow | sym::noop_method_clone | sym::noop_method_deref
- ) {
- return;
- }
+
let receiver_ty = cx.typeck_results().expr_ty(receiver);
let expr_ty = cx.typeck_results().expr_ty_adjusted(expr);
- if receiver_ty != expr_ty {
- // This lint will only trigger if the receiver type and resulting expression \
- // type are the same, implying that the method call is unnecessary.
+ let arg_adjustments = cx.typeck_results().expr_adjustments(receiver);
+
+ // If there is any user defined auto-deref step, then we don't want to warn.
+ // https://github.com/rust-lang/rust-clippy/issues/9272
+ if arg_adjustments.iter().any(|adj| matches!(adj.kind, Adjust::Deref(Some(_)))) {
return;
}
+
let expr_span = expr.span;
let span = expr_span.with_lo(receiver.span.hi());
- cx.emit_spanned_lint(
- NOOP_METHOD_CALL,
- span,
- NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
- );
+
+ if receiver_ty == expr_ty {
+ cx.emit_spanned_lint(
+ NOOP_METHOD_CALL,
+ span,
+ NoopMethodCallDiag { method: call.ident.name, receiver_ty, label: span },
+ );
+ } else {
+ match name {
+ // If `type_of(x) == T` and `x.borrow()` is used to get `&T`,
+ // then that should be allowed
+ sym::noop_method_borrow => return,
+ sym::noop_method_clone => cx.emit_spanned_lint(
+ SUSPICIOUS_DOUBLE_REF_OP,
+ span,
+ SuspiciousDoubleRefCloneDiag { ty: expr_ty },
+ ),
+ sym::noop_method_deref => cx.emit_spanned_lint(
+ SUSPICIOUS_DOUBLE_REF_OP,
+ span,
+ SuspiciousDoubleRefDerefDiag { ty: expr_ty },
+ ),
+ _ => return,
+ }
+ }
}
}
diff --git a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
index f9d43fe22..15715c8fc 100644
--- a/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
+++ b/compiler/rustc_lint/src/opaque_hidden_inferred_bound.rs
@@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
// For every projection predicate in the opaque type's explicit bounds,
// check that the type that we're assigning actually satisfies the bounds
// of the associated type.
- for &(pred, pred_span) in cx.tcx.explicit_item_bounds(def_id) {
+ for (pred, pred_span) in cx.tcx.explicit_item_bounds(def_id).subst_identity_iter_copied() {
// Liberate bound regions in the predicate since we
// don't actually care about lifetimes in this check.
let predicate = cx.tcx.liberate_late_bound_regions(def_id, pred.kind());
@@ -112,7 +112,7 @@ impl<'tcx> LateLintPass<'tcx> for OpaqueHiddenInferredBound {
// with `impl Send: OtherTrait`.
for (assoc_pred, assoc_pred_span) in cx
.tcx
- .bound_explicit_item_bounds(proj.projection_ty.def_id)
+ .explicit_item_bounds(proj.projection_ty.def_id)
.subst_iter_copied(cx.tcx, &proj.projection_ty.substs)
{
let assoc_pred = assoc_pred.fold_with(proj_replacer);
diff --git a/compiler/rustc_lint/src/types.rs b/compiler/rustc_lint/src/types.rs
index a6ba74220..4bf4fda82 100644
--- a/compiler/rustc_lint/src/types.rs
+++ b/compiler/rustc_lint/src/types.rs
@@ -677,7 +677,7 @@ pub fn transparent_newtype_field<'a, 'tcx>(
let param_env = tcx.param_env(variant.def_id);
variant.fields.iter().find(|field| {
let field_ty = tcx.type_of(field.did).subst_identity();
- let is_zst = tcx.layout_of(param_env.and(field_ty)).map_or(false, |layout| layout.is_zst());
+ let is_zst = tcx.layout_of(param_env.and(field_ty)).is_ok_and(|layout| layout.is_zst());
!is_zst
})
}
@@ -1119,14 +1119,14 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> {
// `extern "C" fn` functions can have type parameters, which may or may not be FFI-safe,
// so they are currently ignored for the purposes of this lint.
- ty::Param(..) | ty::Alias(ty::Projection, ..)
+ ty::Param(..) | ty::Alias(ty::Projection | ty::Inherent, ..)
if matches!(self.mode, CItemKind::Definition) =>
{
FfiSafe
}
ty::Param(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Infer(..)
| ty::Bound(..)
| ty::Error(_)
diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs
index 28cc63198..8f75fa11d 100644
--- a/compiler/rustc_lint/src/unused.rs
+++ b/compiler/rustc_lint/src/unused.rs
@@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults {
}
ty::Adt(def, _) => is_def_must_use(cx, def.did(), span),
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
- elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).iter().cloned())
+ elaborate(cx.tcx, cx.tcx.explicit_item_bounds(def).subst_identity_iter_copied())
// We only care about self bounds for the impl-trait
.filter_only_self()
.find_map(|(pred, _span)| {
@@ -571,36 +571,50 @@ trait UnusedDelimLint {
}
}
- // Prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`
- let lhs_needs_parens = {
+ // Check if LHS needs parens to prevent false-positives in cases like `fn x() -> u8 { ({ 0 } + 1) }`.
+ {
let mut innermost = inner;
loop {
innermost = match &innermost.kind {
- ExprKind::Binary(_, lhs, _rhs) => lhs,
+ ExprKind::Binary(_op, lhs, _rhs) => lhs,
ExprKind::Call(fn_, _params) => fn_,
ExprKind::Cast(expr, _ty) => expr,
ExprKind::Type(expr, _ty) => expr,
ExprKind::Index(base, _subscript) => base,
- _ => break false,
+ _ => break,
};
if !classify::expr_requires_semi_to_be_stmt(innermost) {
- break true;
+ return true;
}
}
- };
+ }
- lhs_needs_parens
- || (followed_by_block
- && match &inner.kind {
- ExprKind::Ret(_)
- | ExprKind::Break(..)
- | ExprKind::Yield(..)
- | ExprKind::Yeet(..) => true,
- ExprKind::Range(_lhs, Some(rhs), _limits) => {
- matches!(rhs.kind, ExprKind::Block(..))
- }
- _ => parser::contains_exterior_struct_lit(&inner),
- })
+ // Check if RHS needs parens to prevent false-positives in cases like `if (() == return) {}`.
+ if !followed_by_block {
+ return false;
+ }
+ let mut innermost = inner;
+ loop {
+ innermost = match &innermost.kind {
+ ExprKind::Unary(_op, expr) => expr,
+ ExprKind::Binary(_op, _lhs, rhs) => rhs,
+ ExprKind::AssignOp(_op, _lhs, rhs) => rhs,
+ ExprKind::Assign(_lhs, rhs, _span) => rhs,
+
+ ExprKind::Ret(_) | ExprKind::Yield(..) | ExprKind::Yeet(..) => return true,
+
+ ExprKind::Break(_label, None) => return false,
+ ExprKind::Break(_label, Some(break_expr)) => {
+ return matches!(break_expr.kind, ExprKind::Block(..));
+ }
+
+ ExprKind::Range(_lhs, Some(rhs), _limits) => {
+ return matches!(rhs.kind, ExprKind::Block(..));
+ }
+
+ _ => return parser::contains_exterior_struct_lit(&inner),
+ }
+ }
}
fn emit_unused_delims_expr(
@@ -638,26 +652,20 @@ trait UnusedDelimLint {
return;
}
let spans = match value.kind {
- ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => {
- if let Some(span) = block.stmts[0].span.find_ancestor_inside(value.span) {
- Some((value.span.with_hi(span.lo()), value.span.with_lo(span.hi())))
- } else {
- None
- }
- }
+ ast::ExprKind::Block(ref block, None) if block.stmts.len() == 1 => block.stmts[0]
+ .span
+ .find_ancestor_inside(value.span)
+ .map(|span| (value.span.with_hi(span.lo()), value.span.with_lo(span.hi()))),
ast::ExprKind::Paren(ref expr) => {
- let expr_span = expr.span.find_ancestor_inside(value.span);
- if let Some(expr_span) = expr_span {
- Some((value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi())))
- } else {
- None
- }
+ expr.span.find_ancestor_inside(value.span).map(|expr_span| {
+ (value.span.with_hi(expr_span.lo()), value.span.with_lo(expr_span.hi()))
+ })
}
_ => return,
};
let keep_space = (
- left_pos.map_or(false, |s| s >= value.span.lo()),
- right_pos.map_or(false, |s| s <= value.span.hi()),
+ left_pos.is_some_and(|s| s >= value.span.lo()),
+ right_pos.is_some_and(|s| s <= value.span.hi()),
);
self.emit_unused_delims(cx, value.span, spans, ctx.into(), keep_space);
}
@@ -930,11 +938,10 @@ impl UnusedParens {
// Otherwise proceed with linting.
_ => {}
}
- let spans = if let Some(inner) = inner.span.find_ancestor_inside(value.span) {
- Some((value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())))
- } else {
- None
- };
+ let spans = inner
+ .span
+ .find_ancestor_inside(value.span)
+ .map(|inner| (value.span.with_hi(inner.lo()), value.span.with_lo(inner.hi())));
self.emit_unused_delims(cx, value.span, spans, "pattern", keep_space);
}
}
@@ -1045,11 +1052,11 @@ impl EarlyLintPass for UnusedParens {
if self.with_self_ty_parens && b.generic_params.len() > 0 => {}
ast::TyKind::ImplTrait(_, bounds) if bounds.len() > 1 => {}
_ => {
- let spans = if let Some(r) = r.span.find_ancestor_inside(ty.span) {
- Some((ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())))
- } else {
- None
- };
+ let spans = r
+ .span
+ .find_ancestor_inside(ty.span)
+ .map(|r| (ty.span.with_hi(r.lo()), ty.span.with_lo(r.hi())));
+
self.emit_unused_delims(cx, ty.span, spans, "type", (false, false));
}
}
diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs
index 9d6ab0b75..6e9dc880a 100644
--- a/compiler/rustc_lint_defs/src/builtin.rs
+++ b/compiler/rustc_lint_defs/src/builtin.rs
@@ -333,6 +333,7 @@ declare_lint! {
///
/// ```rust,compile_fail
/// #![deny(unused_extern_crates)]
+ /// #![deny(warnings)]
/// extern crate proc_macro;
/// ```
///
@@ -1021,7 +1022,7 @@ declare_lint! {
declare_lint! {
/// The `invalid_alignment` lint detects dereferences of misaligned pointers during
- /// constant evluation.
+ /// constant evaluation.
///
/// ### Example
///
@@ -1667,6 +1668,7 @@ declare_lint! {
///
/// ```rust,compile_fail
/// #![deny(elided_lifetimes_in_paths)]
+ /// #![deny(warnings)]
/// struct Foo<'a> {
/// x: &'a u32
/// }
@@ -1854,7 +1856,7 @@ declare_lint! {
/// When new methods are added to traits in the standard library, they are
/// usually added in an "unstable" form which is only available on the
/// [nightly channel] with a [`feature` attribute]. If there is any
- /// pre-existing code which extends a trait to have a method with the same
+ /// preexisting code which extends a trait to have a method with the same
/// name, then the names will collide. In the future, when the method is
/// stabilized, this will cause an error due to the ambiguity. This lint
/// is an early-warning to let you know that there may be a collision in
@@ -2158,6 +2160,7 @@ declare_lint! {
/// ```rust,compile_fail
/// # #![allow(unused)]
/// #![deny(explicit_outlives_requirements)]
+ /// #![deny(warnings)]
///
/// struct SharedRef<'a, T>
/// where
@@ -3273,110 +3276,115 @@ declare_lint_pass! {
/// Does nothing as a lint pass, but registers some `Lint`s
/// that are used by other parts of the compiler.
HardwiredLints => [
- FORBIDDEN_LINT_GROUPS,
- ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ // tidy-alphabetical-start
+ ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
+ AMBIGUOUS_ASSOCIATED_ITEMS,
+ AMBIGUOUS_GLOB_REEXPORTS,
ARITHMETIC_OVERFLOW,
- UNCONDITIONAL_PANIC,
- UNUSED_IMPORTS,
- UNUSED_EXTERN_CRATES,
- UNUSED_CRATE_DEPENDENCIES,
- UNUSED_QUALIFICATIONS,
- UNKNOWN_LINTS,
- UNFULFILLED_LINT_EXPECTATIONS,
- UNUSED_VARIABLES,
- UNUSED_ASSIGNMENTS,
- DEAD_CODE,
- UNREACHABLE_CODE,
- UNREACHABLE_PATTERNS,
- OVERLAPPING_RANGE_ENDPOINTS,
+ ASM_SUB_REGISTER,
+ BAD_ASM_STYLE,
+ BARE_TRAIT_OBJECTS,
BINDINGS_WITH_VARIANT_NAME,
- UNUSED_MACROS,
- UNUSED_MACRO_RULES,
- WARNINGS,
- UNUSED_FEATURES,
- STABLE_FEATURES,
- UNKNOWN_CRATE_TYPES,
- TRIVIAL_CASTS,
- TRIVIAL_NUMERIC_CASTS,
- PRIVATE_IN_PUBLIC,
- EXPORTED_PRIVATE_DEPENDENCIES,
- PUB_USE_OF_PRIVATE_EXTERN_CRATE,
- INVALID_TYPE_PARAM_DEFAULT,
- RENAMED_AND_REMOVED_LINTS,
- CONST_ITEM_MUTATION,
- PATTERNS_IN_FNS_WITHOUT_BODY,
- MISSING_FRAGMENT_SPECIFIER,
- LATE_BOUND_LIFETIME_ARGUMENTS,
- ORDER_DEPENDENT_TRAIT_OBJECTS,
+ BREAK_WITH_LABEL_AND_LOOP,
+ BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
+ CENUM_IMPL_DROP_CAST,
COHERENCE_LEAK_CHECK,
+ CONFLICTING_REPR_HINTS,
+ CONST_EVALUATABLE_UNCHECKED,
+ CONST_ITEM_MUTATION,
+ DEAD_CODE,
DEPRECATED,
- UNUSED_UNSAFE,
- UNUSED_MUT,
- UNCONDITIONAL_RECURSION,
- SINGLE_USE_LIFETIMES,
- UNUSED_LIFETIMES,
- UNUSED_LABELS,
- TYVAR_BEHIND_RAW_POINTER,
+ DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
+ DEPRECATED_IN_FUTURE,
+ DEPRECATED_WHERE_CLAUSE_LOCATION,
+ DUPLICATE_MACRO_ATTRIBUTES,
ELIDED_LIFETIMES_IN_PATHS,
- BARE_TRAIT_OBJECTS,
- ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE,
- UNSTABLE_NAME_COLLISIONS,
- IRREFUTABLE_LET_PATTERNS,
- WHERE_CLAUSES_OBJECT_SAFETY,
- PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
- MACRO_USE_EXTERN_CRATE,
- MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+ EXPORTED_PRIVATE_DEPENDENCIES,
+ FFI_UNWIND_CALLS,
+ FORBIDDEN_LINT_GROUPS,
+ FUNCTION_ITEM_REFERENCES,
+ FUZZY_PROVENANCE_CASTS,
ILL_FORMED_ATTRIBUTE_INPUT,
- CONFLICTING_REPR_HINTS,
- META_VARIABLE_MISUSE,
- DEPRECATED_IN_FUTURE,
- AMBIGUOUS_ASSOCIATED_ITEMS,
- INDIRECT_STRUCTURAL_MATCH,
- POINTER_STRUCTURAL_MATCH,
- NONTRIVIAL_STRUCTURAL_MATCH,
- SOFT_UNSTABLE,
- UNSTABLE_SYNTAX_PRE_EXPANSION,
- INLINE_NO_SANITIZE,
- BAD_ASM_STYLE,
- ASM_SUB_REGISTER,
- UNSAFE_OP_IN_UNSAFE_FN,
+ ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ IMPLIED_BOUNDS_ENTAILMENT,
INCOMPLETE_INCLUDE,
- CENUM_IMPL_DROP_CAST,
- FUZZY_PROVENANCE_CASTS,
- LOSSY_PROVENANCE_CASTS,
- CONST_EVALUATABLE_UNCHECKED,
+ INDIRECT_STRUCTURAL_MATCH,
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
- MUST_NOT_SUSPEND,
- UNINHABITED_STATIC,
- FUNCTION_ITEM_REFERENCES,
- USELESS_DEPRECATED,
- MISSING_ABI,
+ INLINE_NO_SANITIZE,
+ INVALID_ALIGNMENT,
INVALID_DOC_ATTRIBUTES,
- SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
- RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
+ INVALID_MACRO_EXPORT_ARGUMENTS,
+ INVALID_TYPE_PARAM_DEFAULT,
+ IRREFUTABLE_LET_PATTERNS,
+ LARGE_ASSIGNMENTS,
+ LATE_BOUND_LIFETIME_ARGUMENTS,
LEGACY_DERIVE_HELPERS,
+ LOSSY_PROVENANCE_CASTS,
+ MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS,
+ MACRO_USE_EXTERN_CRATE,
+ META_VARIABLE_MISUSE,
+ MISSING_ABI,
+ MISSING_FRAGMENT_SPECIFIER,
+ MUST_NOT_SUSPEND,
+ NAMED_ARGUMENTS_USED_POSITIONALLY,
+ NON_EXHAUSTIVE_OMITTED_PATTERNS,
+ NONTRIVIAL_STRUCTURAL_MATCH,
+ ORDER_DEPENDENT_TRAIT_OBJECTS,
+ OVERLAPPING_RANGE_ENDPOINTS,
+ PATTERNS_IN_FNS_WITHOUT_BODY,
+ POINTER_STRUCTURAL_MATCH,
+ PRIVATE_IN_PUBLIC,
PROC_MACRO_BACK_COMPAT,
+ PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
+ PUB_USE_OF_PRIVATE_EXTERN_CRATE,
+ RENAMED_AND_REMOVED_LINTS,
+ REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
+ RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES,
RUST_2021_INCOMPATIBLE_OR_PATTERNS,
- LARGE_ASSIGNMENTS,
- RUST_2021_PRELUDE_COLLISIONS,
RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
+ RUST_2021_PRELUDE_COLLISIONS,
+ SEMICOLON_IN_EXPRESSIONS_FROM_MACROS,
+ SINGLE_USE_LIFETIMES,
+ SOFT_UNSTABLE,
+ STABLE_FEATURES,
+ SUSPICIOUS_AUTO_TRAIT_IMPLS,
+ TEST_UNSTABLE_LINT,
+ TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
+ TRIVIAL_CASTS,
+ TRIVIAL_NUMERIC_CASTS,
+ TYVAR_BEHIND_RAW_POINTER,
+ UNCONDITIONAL_PANIC,
+ UNCONDITIONAL_RECURSION,
+ UNDEFINED_NAKED_FUNCTION_ABI,
+ UNFULFILLED_LINT_EXPECTATIONS,
+ UNINHABITED_STATIC,
+ UNKNOWN_CRATE_TYPES,
+ UNKNOWN_LINTS,
+ UNREACHABLE_CODE,
+ UNREACHABLE_PATTERNS,
+ UNSAFE_OP_IN_UNSAFE_FN,
+ UNSTABLE_NAME_COLLISIONS,
+ UNSTABLE_SYNTAX_PRE_EXPANSION,
UNSUPPORTED_CALLING_CONVENTIONS,
- BREAK_WITH_LABEL_AND_LOOP,
+ UNUSED_ASSIGNMENTS,
UNUSED_ATTRIBUTES,
+ UNUSED_CRATE_DEPENDENCIES,
+ UNUSED_EXTERN_CRATES,
+ UNUSED_FEATURES,
+ UNUSED_IMPORTS,
+ UNUSED_LABELS,
+ UNUSED_LIFETIMES,
+ UNUSED_MACRO_RULES,
+ UNUSED_MACROS,
+ UNUSED_MUT,
+ UNUSED_QUALIFICATIONS,
UNUSED_TUPLE_STRUCT_FIELDS,
- NON_EXHAUSTIVE_OMITTED_PATTERNS,
- TEXT_DIRECTION_CODEPOINT_IN_COMMENT,
- DEPRECATED_CFG_ATTR_CRATE_TYPE_NAME,
- DUPLICATE_MACRO_ATTRIBUTES,
- SUSPICIOUS_AUTO_TRAIT_IMPLS,
- DEPRECATED_WHERE_CLAUSE_LOCATION,
- TEST_UNSTABLE_LINT,
- FFI_UNWIND_CALLS,
- REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS,
- NAMED_ARGUMENTS_USED_POSITIONALLY,
- IMPLIED_BOUNDS_ENTAILMENT,
- BYTE_SLICE_IN_PACKED_STRUCT_WITH_DERIVE,
- AMBIGUOUS_GLOB_REEXPORTS,
+ UNUSED_UNSAFE,
+ UNUSED_VARIABLES,
+ USELESS_DEPRECATED,
+ WARNINGS,
+ WHERE_CLAUSES_OBJECT_SAFETY,
+ // tidy-alphabetical-end
]
}
@@ -4009,7 +4017,6 @@ declare_lint! {
/// ### Example
///
/// ```rust
- /// #![feature(c_unwind)]
/// #![warn(ffi_unwind_calls)]
///
/// extern "C-unwind" {
@@ -4032,8 +4039,7 @@ declare_lint! {
/// that desire this ability it is therefore necessary to avoid such calls.
pub FFI_UNWIND_CALLS,
Allow,
- "call to foreign functions or function pointers with FFI-unwind ABI",
- @feature_gate = sym::c_unwind;
+ "call to foreign functions or function pointers with FFI-unwind ABI"
}
declare_lint! {
diff --git a/compiler/rustc_lint_defs/src/lib.rs b/compiler/rustc_lint_defs/src/lib.rs
index 7ea472ed5..e27e322db 100644
--- a/compiler/rustc_lint_defs/src/lib.rs
+++ b/compiler/rustc_lint_defs/src/lib.rs
@@ -496,7 +496,8 @@ pub enum BuiltinLintDiagnostics {
BreakWithLabelAndLoop(Span),
NamedAsmLabel(String),
UnicodeTextFlow(Span, String),
- UnexpectedCfg((Symbol, Span), Option<(Symbol, Span)>),
+ UnexpectedCfgName((Symbol, Span), Option<(Symbol, Span)>),
+ UnexpectedCfgValue((Symbol, Span), Option<(Symbol, Span)>),
DeprecatedWhereclauseLocation(Span, String),
SingleUseLifetime {
/// Span of the parameter which declares this lifetime.
diff --git a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
index 448a1f62f..35d6b9ed7 100644
--- a/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp
@@ -39,6 +39,7 @@ enum class LLVMRustArchiveKind {
BSD,
DARWIN,
COFF,
+ AIX_BIG,
};
static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
@@ -51,6 +52,8 @@ static Archive::Kind fromRust(LLVMRustArchiveKind Kind) {
return Archive::K_DARWIN;
case LLVMRustArchiveKind::COFF:
return Archive::K_COFF;
+ case LLVMRustArchiveKind::AIX_BIG:
+ return Archive::K_AIXBIG;
default:
report_fatal_error("Bad ArchiveKind.");
}
diff --git a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
index 03e6d2149..87906dee4 100644
--- a/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp
@@ -8,18 +8,100 @@
using namespace llvm;
+// FFI equivalent of enum `llvm::coverage::Counter::CounterKind`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L97-L99
+enum class LLVMRustCounterKind {
+ Zero = 0,
+ CounterValueReference = 1,
+ Expression = 2,
+};
+
+// FFI equivalent of struct `llvm::coverage::Counter`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L94-L149
+struct LLVMRustCounter {
+ LLVMRustCounterKind CounterKind;
+ uint32_t ID;
+};
+
+static coverage::Counter fromRust(LLVMRustCounter Counter) {
+ switch (Counter.CounterKind) {
+ case LLVMRustCounterKind::Zero:
+ return coverage::Counter::getZero();
+ case LLVMRustCounterKind::CounterValueReference:
+ return coverage::Counter::getCounter(Counter.ID);
+ case LLVMRustCounterKind::Expression:
+ return coverage::Counter::getExpression(Counter.ID);
+ }
+ report_fatal_error("Bad LLVMRustCounterKind!");
+}
+
+// FFI equivalent of enum `llvm::coverage::CounterMappingRegion::RegionKind`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L213-L234
+enum class LLVMRustCounterMappingRegionKind {
+ CodeRegion = 0,
+ ExpansionRegion = 1,
+ SkippedRegion = 2,
+ GapRegion = 3,
+ BranchRegion = 4,
+};
+
+static coverage::CounterMappingRegion::RegionKind
+fromRust(LLVMRustCounterMappingRegionKind Kind) {
+ switch (Kind) {
+ case LLVMRustCounterMappingRegionKind::CodeRegion:
+ return coverage::CounterMappingRegion::CodeRegion;
+ case LLVMRustCounterMappingRegionKind::ExpansionRegion:
+ return coverage::CounterMappingRegion::ExpansionRegion;
+ case LLVMRustCounterMappingRegionKind::SkippedRegion:
+ return coverage::CounterMappingRegion::SkippedRegion;
+ case LLVMRustCounterMappingRegionKind::GapRegion:
+ return coverage::CounterMappingRegion::GapRegion;
+ case LLVMRustCounterMappingRegionKind::BranchRegion:
+ return coverage::CounterMappingRegion::BranchRegion;
+ }
+ report_fatal_error("Bad LLVMRustCounterMappingRegionKind!");
+}
+
+// FFI equivalent of struct `llvm::coverage::CounterMappingRegion`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L211-L304
struct LLVMRustCounterMappingRegion {
- coverage::Counter Count;
- coverage::Counter FalseCount;
+ LLVMRustCounter Count;
+ LLVMRustCounter FalseCount;
uint32_t FileID;
uint32_t ExpandedFileID;
uint32_t LineStart;
uint32_t ColumnStart;
uint32_t LineEnd;
uint32_t ColumnEnd;
- coverage::CounterMappingRegion::RegionKind Kind;
+ LLVMRustCounterMappingRegionKind Kind;
+};
+
+// FFI equivalent of enum `llvm::coverage::CounterExpression::ExprKind`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L154
+enum class LLVMRustCounterExprKind {
+ Subtract = 0,
+ Add = 1,
};
+// FFI equivalent of struct `llvm::coverage::CounterExpression`
+// https://github.com/rust-lang/llvm-project/blob/ea6fa9c2/llvm/include/llvm/ProfileData/Coverage/CoverageMapping.h#L151-L160
+struct LLVMRustCounterExpression {
+ LLVMRustCounterExprKind Kind;
+ LLVMRustCounter LHS;
+ LLVMRustCounter RHS;
+};
+
+static coverage::CounterExpression::ExprKind
+fromRust(LLVMRustCounterExprKind Kind) {
+ switch (Kind) {
+ case LLVMRustCounterExprKind::Subtract:
+ return coverage::CounterExpression::Subtract;
+ case LLVMRustCounterExprKind::Add:
+ return coverage::CounterExpression::Add;
+ }
+ report_fatal_error("Bad LLVMRustCounterExprKind!");
+}
+
extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
const char* const Filenames[],
size_t FilenamesLen,
@@ -37,9 +119,9 @@ extern "C" void LLVMRustCoverageWriteFilenamesSectionToBuffer(
extern "C" void LLVMRustCoverageWriteMappingToBuffer(
const unsigned *VirtualFileMappingIDs,
unsigned NumVirtualFileMappingIDs,
- const coverage::CounterExpression *Expressions,
+ const LLVMRustCounterExpression *RustExpressions,
unsigned NumExpressions,
- LLVMRustCounterMappingRegion *RustMappingRegions,
+ const LLVMRustCounterMappingRegion *RustMappingRegions,
unsigned NumMappingRegions,
RustStringRef BufferOut) {
// Convert from FFI representation to LLVM representation.
@@ -48,13 +130,24 @@ extern "C" void LLVMRustCoverageWriteMappingToBuffer(
for (const auto &Region : ArrayRef<LLVMRustCounterMappingRegion>(
RustMappingRegions, NumMappingRegions)) {
MappingRegions.emplace_back(
- Region.Count, Region.FalseCount, Region.FileID, Region.ExpandedFileID,
+ fromRust(Region.Count), fromRust(Region.FalseCount),
+ Region.FileID, Region.ExpandedFileID,
Region.LineStart, Region.ColumnStart, Region.LineEnd, Region.ColumnEnd,
- Region.Kind);
+ fromRust(Region.Kind));
}
+
+ std::vector<coverage::CounterExpression> Expressions;
+ Expressions.reserve(NumExpressions);
+ for (const auto &Expression :
+ ArrayRef<LLVMRustCounterExpression>(RustExpressions, NumExpressions)) {
+ Expressions.emplace_back(fromRust(Expression.Kind),
+ fromRust(Expression.LHS),
+ fromRust(Expression.RHS));
+ }
+
auto CoverageMappingWriter = coverage::CoverageMappingWriter(
ArrayRef<unsigned>(VirtualFileMappingIDs, NumVirtualFileMappingIDs),
- ArrayRef<coverage::CounterExpression>(Expressions, NumExpressions),
+ Expressions,
MappingRegions);
RawRustStringOstream OS(BufferOut);
CoverageMappingWriter.write(OS);
diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
index 08e38b0c9..c43a02724 100644
--- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
+++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp
@@ -297,7 +297,6 @@ static Reloc::Model fromRust(LLVMRustRelocModel RustReloc) {
report_fatal_error("Bad RelocModel.");
}
-#ifdef LLVM_RUSTLLVM
/// getLongestEntryLength - Return the length of the longest entry in the table.
template<typename KV>
static size_t getLongestEntryLength(ArrayRef<KV> Table) {
@@ -307,54 +306,68 @@ static size_t getLongestEntryLength(ArrayRef<KV> Table) {
return MaxLen;
}
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM) {
+extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef TM, const char* TargetCPU) {
const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
- const Triple::ArchType HostArch = Triple(sys::getProcessTriple()).getArch();
+ const Triple::ArchType HostArch = Triple(sys::getDefaultTargetTriple()).getArch();
const Triple::ArchType TargetArch = Target->getTargetTriple().getArch();
+
+#if LLVM_VERSION_GE(17, 0)
+ const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getAllProcessorDescriptions();
+#elif defined(LLVM_RUSTLLVM)
const ArrayRef<SubtargetSubTypeKV> CPUTable = MCInfo->getCPUTable();
+#else
+ printf("Full target CPU help is not supported by this LLVM version.\n\n");
+ SubtargetSubTypeKV TargetCPUKV = { TargetCPU, {{}}, {{}} };
+ const ArrayRef<SubtargetSubTypeKV> CPUTable = TargetCPUKV;
+#endif
unsigned MaxCPULen = getLongestEntryLength(CPUTable);
printf("Available CPUs for this target:\n");
+ // Don't print the "native" entry when the user specifies --target with a
+ // different arch since that could be wrong or misleading.
if (HostArch == TargetArch) {
+ MaxCPULen = std::max(MaxCPULen, (unsigned) std::strlen("native"));
const StringRef HostCPU = sys::getHostCPUName();
printf(" %-*s - Select the CPU of the current host (currently %.*s).\n",
MaxCPULen, "native", (int)HostCPU.size(), HostCPU.data());
}
- for (auto &CPU : CPUTable)
- printf(" %-*s\n", MaxCPULen, CPU.Key);
- printf("\n");
+ for (auto &CPU : CPUTable) {
+ // Compare cpu against current target to label the default
+ if (strcmp(CPU.Key, TargetCPU) == 0) {
+ printf(" %-*s - This is the default target CPU"
+ " for the current build target (currently %s).",
+ MaxCPULen, CPU.Key, Target->getTargetTriple().str().c_str());
+ }
+ else {
+ printf(" %-*s", MaxCPULen, CPU.Key);
+ }
+ printf("\n");
+ }
}
extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef TM) {
+#ifdef LLVM_RUSTLLVM
const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
return FeatTable.size();
+#else
+ return 0;
+#endif
}
extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef TM, size_t Index,
const char** Feature, const char** Desc) {
+#ifdef LLVM_RUSTLLVM
const TargetMachine *Target = unwrap(TM);
const MCSubtargetInfo *MCInfo = Target->getMCSubtargetInfo();
const ArrayRef<SubtargetFeatureKV> FeatTable = MCInfo->getFeatureTable();
const SubtargetFeatureKV Feat = FeatTable[Index];
*Feature = Feat.Key;
*Desc = Feat.Desc;
-}
-
-#else
-
-extern "C" void LLVMRustPrintTargetCPUs(LLVMTargetMachineRef) {
- printf("Target CPU help is not supported by this LLVM version.\n\n");
-}
-
-extern "C" size_t LLVMRustGetTargetFeaturesCount(LLVMTargetMachineRef) {
- return 0;
-}
-
-extern "C" void LLVMRustGetTargetFeature(LLVMTargetMachineRef, const char**, const char**) {}
#endif
+}
extern "C" const char* LLVMRustGetHostCPUName(size_t *len) {
StringRef Name = sys::getHostCPUName();
@@ -408,10 +421,15 @@ extern "C" LLVMTargetMachineRef LLVMRustCreateTargetMachine(
}
Options.RelaxELFRelocations = RelaxELFRelocations;
Options.UseInitArray = UseInitArray;
+
+#if LLVM_VERSION_LT(17, 0)
if (ForceEmulatedTls) {
Options.ExplicitEmulatedTLS = true;
Options.EmulatedTLS = true;
}
+#else
+ Options.EmulatedTLS = ForceEmulatedTls || Trip.hasDefaultEmulatedTLS();
+#endif
if (TrapUnreachable) {
// Tell LLVM to codegen `unreachable` into an explicit trap instruction.
@@ -523,14 +541,14 @@ extern "C" typedef void (*LLVMRustSelfProfileBeforePassCallback)(void*, // LlvmS
extern "C" typedef void (*LLVMRustSelfProfileAfterPassCallback)(void*); // LlvmSelfProfiler
std::string LLVMRustwrappedIrGetName(const llvm::Any &WrappedIr) {
- if (any_isa<const Module *>(WrappedIr))
- return any_cast<const Module *>(WrappedIr)->getName().str();
- if (any_isa<const Function *>(WrappedIr))
- return any_cast<const Function *>(WrappedIr)->getName().str();
- if (any_isa<const Loop *>(WrappedIr))
- return any_cast<const Loop *>(WrappedIr)->getName().str();
- if (any_isa<const LazyCallGraph::SCC *>(WrappedIr))
- return any_cast<const LazyCallGraph::SCC *>(WrappedIr)->getName();
+ if (const auto *Cast = any_cast<const Module *>(&WrappedIr))
+ return (*Cast)->getName().str();
+ if (const auto *Cast = any_cast<const Function *>(&WrappedIr))
+ return (*Cast)->getName().str();
+ if (const auto *Cast = any_cast<const Loop *>(&WrappedIr))
+ return (*Cast)->getName().str();
+ if (const auto *Cast = any_cast<const LazyCallGraph::SCC *>(&WrappedIr))
+ return (*Cast)->getName();
return "<UNKNOWN>";
}
@@ -727,6 +745,9 @@ LLVMRustOptimize(
if (InstrProfileOutput) {
Options.InstrProfileOutput = InstrProfileOutput;
}
+ // cargo run tests in multhreading mode by default
+ // so use atomics for coverage counters
+ Options.Atomic = true;
MPM.addPass(InstrProfiling(Options, false));
}
);
@@ -811,7 +832,7 @@ LLVMRustOptimize(
ModulePassManager MPM;
bool NeedThinLTOBufferPasses = UseThinLTOBuffers;
if (!NoPrepopulatePasses) {
- // The pre-link pipelines don't support O0 and require using budilO0DefaultPipeline() instead.
+ // The pre-link pipelines don't support O0 and require using buildO0DefaultPipeline() instead.
// At the same time, the LTO pipelines do support O0 and using them is required.
bool IsLTO = OptStage == LLVMRustOptStage::ThinLTO || OptStage == LLVMRustOptStage::FatLTO;
if (OptLevel == OptimizationLevel::O0 && !IsLTO) {
@@ -1442,63 +1463,6 @@ LLVMRustGetBitcodeSliceFromObjectData(const char *data,
return BitcodeOrError->getBufferStart();
}
-// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
-// the comment in `back/lto.rs` for why this exists.
-extern "C" void
-LLVMRustThinLTOGetDICompileUnit(LLVMModuleRef Mod,
- DICompileUnit **A,
- DICompileUnit **B) {
- Module *M = unwrap(Mod);
- DICompileUnit **Cur = A;
- DICompileUnit **Next = B;
- for (DICompileUnit *CU : M->debug_compile_units()) {
- *Cur = CU;
- Cur = Next;
- Next = nullptr;
- if (Cur == nullptr)
- break;
- }
-}
-
-// Rewrite all `DICompileUnit` pointers to the `DICompileUnit` specified. See
-// the comment in `back/lto.rs` for why this exists.
-extern "C" void
-LLVMRustThinLTOPatchDICompileUnit(LLVMModuleRef Mod, DICompileUnit *Unit) {
- Module *M = unwrap(Mod);
-
- // If the original source module didn't have a `DICompileUnit` then try to
- // merge all the existing compile units. If there aren't actually any though
- // then there's not much for us to do so return.
- if (Unit == nullptr) {
- for (DICompileUnit *CU : M->debug_compile_units()) {
- Unit = CU;
- break;
- }
- if (Unit == nullptr)
- return;
- }
-
- // Use LLVM's built-in `DebugInfoFinder` to find a bunch of debuginfo and
- // process it recursively. Note that we used to specifically iterate over
- // instructions to ensure we feed everything into it, but `processModule`
- // started doing this the same way in LLVM 7 (commit d769eb36ab2b8).
- DebugInfoFinder Finder;
- Finder.processModule(*M);
-
- // After we've found all our debuginfo, rewrite all subprograms to point to
- // the same `DICompileUnit`.
- for (auto &F : Finder.subprograms()) {
- F->replaceUnit(Unit);
- }
-
- // Erase any other references to other `DICompileUnit` instances, the verifier
- // will later ensure that we don't actually have any other stale references to
- // worry about.
- auto *MD = M->getNamedMetadata("llvm.dbg.cu");
- MD->clearOperands();
- MD->addOperand(Unit);
-}
-
// Computes the LTO cache key for the provided 'ModId' in the given 'Data',
// storing the result in 'KeyOut'.
// Currently, this cache key is a SHA-1 hash of anything that could affect
diff --git a/compiler/rustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml
index 745983e7e..1f1201b00 100644
--- a/compiler/rustc_macros/Cargo.toml
+++ b/compiler/rustc_macros/Cargo.toml
@@ -7,11 +7,7 @@ edition = "2021"
proc-macro = true
[dependencies]
-annotate-snippets = "0.9"
-fluent-bundle = "0.15.2"
-fluent-syntax = "0.11"
synstructure = "0.13.0"
syn = { version = "2", features = ["full"] }
proc-macro2 = "1"
quote = "1"
-unic-langid = { version = "0.9.0", features = ["macros"] }
diff --git a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
index 427c82c41..cd6e36874 100644
--- a/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
+++ b/compiler/rustc_macros/src/diagnostics/diagnostic_builder.rs
@@ -9,7 +9,7 @@ use crate::diagnostics::utils::{
FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
};
use proc_macro2::{Ident, Span, TokenStream};
-use quote::{format_ident, quote};
+use quote::{format_ident, quote, quote_spanned};
use syn::Token;
use syn::{parse_quote, spanned::Spanned, Attribute, Meta, Path, Type};
use synstructure::{BindingInfo, Structure, VariantInfo};
@@ -251,7 +251,8 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
let diag = &self.parent.diag;
let field = binding_info.ast();
- let field_binding = &binding_info.binding;
+ let mut field_binding = binding_info.binding.clone();
+ field_binding.set_span(field.ty.span());
let ident = field.ident.as_ref().unwrap();
let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
@@ -284,9 +285,9 @@ impl<'a> DiagnosticDeriveVariantBuilder<'a> {
name == "primary_span" && matches!(inner_ty, FieldInnerTy::Vec(_));
let (binding, needs_destructure) = if needs_clone {
// `primary_span` can accept a `Vec<Span>` so don't destructure that.
- (quote! { #field_binding.clone() }, false)
+ (quote_spanned! {inner_ty.span()=> #field_binding.clone() }, false)
} else {
- (quote! { #field_binding }, true)
+ (quote_spanned! {inner_ty.span()=> #field_binding }, true)
};
let generated_code = self
diff --git a/compiler/rustc_macros/src/diagnostics/mod.rs b/compiler/rustc_macros/src/diagnostics/mod.rs
index 78df0cd1d..a536eb3b0 100644
--- a/compiler/rustc_macros/src/diagnostics/mod.rs
+++ b/compiler/rustc_macros/src/diagnostics/mod.rs
@@ -1,12 +1,10 @@
mod diagnostic;
mod diagnostic_builder;
mod error;
-mod fluent;
mod subdiagnostic;
mod utils;
use diagnostic::{DiagnosticDerive, LintDiagnosticDerive};
-pub(crate) use fluent::fluent_messages;
use proc_macro2::TokenStream;
use quote::format_ident;
use subdiagnostic::SubdiagnosticDeriveBuilder;
@@ -142,7 +140,7 @@ pub fn lint_diagnostic_derive(s: Structure<'_>) -> TokenStream {
/// ```fluent
/// parser_expected_identifier = expected identifier
///
-/// parser_expected_identifier-found = expected identifier, found {$found}
+/// parser_expected_identifier_found = expected identifier, found {$found}
///
/// parser_raw_identifier = escape `{$ident}` to use it as an identifier
/// ```
diff --git a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
index 62d49c1c6..374ba1a45 100644
--- a/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
+++ b/compiler/rustc_macros/src/diagnostics/subdiagnostic.rs
@@ -4,17 +4,16 @@ use crate::diagnostics::error::{
invalid_attr, span_err, throw_invalid_attr, throw_span_err, DiagnosticDeriveError,
};
use crate::diagnostics::utils::{
- build_field_mapping, is_doc_comment, new_code_ident,
- report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span, FieldInfo,
- FieldInnerTy, FieldMap, HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
+ build_field_mapping, build_suggestion_code, is_doc_comment, new_code_ident,
+ report_error_if_not_applied_to_applicability, report_error_if_not_applied_to_span,
+ should_generate_set_arg, AllowMultipleAlternatives, FieldInfo, FieldInnerTy, FieldMap,
+ HasFieldMap, SetOnce, SpannedOption, SubdiagnosticKind,
};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
use syn::{spanned::Spanned, Attribute, Meta, MetaList, Path};
use synstructure::{BindingInfo, Structure, VariantInfo};
-use super::utils::{build_suggestion_code, AllowMultipleAlternatives};
-
/// The central struct for constructing the `add_to_diagnostic` method from an annotated struct.
pub(crate) struct SubdiagnosticDeriveBuilder {
diag: syn::Ident,
@@ -210,19 +209,20 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
}
/// Generates the code for a field with no attributes.
- fn generate_field_set_arg(&mut self, binding: &BindingInfo<'_>) -> TokenStream {
- let ast = binding.ast();
- assert_eq!(ast.attrs.len(), 0, "field with attribute used as diagnostic arg");
-
+ fn generate_field_set_arg(&mut self, binding_info: &BindingInfo<'_>) -> TokenStream {
let diag = &self.parent.diag;
- let ident = ast.ident.as_ref().unwrap();
- // strip `r#` prefix, if present
- let ident = format_ident!("{}", ident);
+
+ let field = binding_info.ast();
+ let mut field_binding = binding_info.binding.clone();
+ field_binding.set_span(field.ty.span());
+
+ let ident = field.ident.as_ref().unwrap();
+ let ident = format_ident!("{}", ident); // strip `r#` prefix, if present
quote! {
#diag.set_arg(
stringify!(#ident),
- #binding
+ #field_binding
);
}
}
@@ -399,7 +399,8 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
clone_suggestion_code: bool,
) -> Result<TokenStream, DiagnosticDeriveError> {
let span = attr.span().unwrap();
- let ident = &list.path.segments.last().unwrap().ident;
+ let mut ident = list.path.segments.last().unwrap().ident.clone();
+ ident.set_span(info.ty.span());
let name = ident.to_string();
let name = name.as_str();
@@ -498,7 +499,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant
.bindings()
.iter()
- .filter(|binding| !binding.ast().attrs.is_empty())
+ .filter(|binding| !should_generate_set_arg(binding.ast()))
.map(|binding| self.generate_field_attr_code(binding, kind_stats))
.collect();
@@ -580,7 +581,7 @@ impl<'parent, 'a> SubdiagnosticDeriveVariantBuilder<'parent, 'a> {
.variant
.bindings()
.iter()
- .filter(|binding| binding.ast().attrs.is_empty())
+ .filter(|binding| should_generate_set_arg(binding.ast()))
.map(|binding| self.generate_field_set_arg(binding))
.collect();
diff --git a/compiler/rustc_macros/src/diagnostics/utils.rs b/compiler/rustc_macros/src/diagnostics/utils.rs
index b9b09c662..e2434981f 100644
--- a/compiler/rustc_macros/src/diagnostics/utils.rs
+++ b/compiler/rustc_macros/src/diagnostics/utils.rs
@@ -207,6 +207,12 @@ impl<'ty> FieldInnerTy<'ty> {
FieldInnerTy::Plain(..) => quote! { #inner },
}
}
+
+ pub fn span(&self) -> proc_macro2::Span {
+ match self {
+ FieldInnerTy::Option(ty) | FieldInnerTy::Vec(ty) | FieldInnerTy::Plain(ty) => ty.span(),
+ }
+ }
}
/// Field information passed to the builder. Deliberately omits attrs to discourage the
@@ -851,7 +857,8 @@ impl quote::IdentFragment for SubdiagnosticKind {
/// Returns `true` if `field` should generate a `set_arg` call rather than any other diagnostic
/// call (like `span_label`).
pub(super) fn should_generate_set_arg(field: &Field) -> bool {
- field.attrs.is_empty()
+ // Perhaps this should be an exhaustive list...
+ field.attrs.iter().all(|attr| is_doc_comment(attr))
}
pub(super) fn is_doc_comment(attr: &Attribute) -> bool {
diff --git a/compiler/rustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs
index 737500cc2..904f8eb57 100644
--- a/compiler/rustc_macros/src/lib.rs
+++ b/compiler/rustc_macros/src/lib.rs
@@ -54,60 +54,6 @@ pub fn newtype_index(input: TokenStream) -> TokenStream {
newtype::newtype(input)
}
-/// Implements the `fluent_messages` macro, which performs compile-time validation of the
-/// compiler's Fluent resources (i.e. that the resources parse and don't multiply define the same
-/// messages) and generates constants that make using those messages in diagnostics more ergonomic.
-///
-/// For example, given the following invocation of the macro..
-///
-/// ```ignore (rust)
-/// fluent_messages! { "./typeck.ftl" }
-/// ```
-/// ..where `typeck.ftl` has the following contents..
-///
-/// ```fluent
-/// typeck_field_multiply_specified_in_initializer =
-/// field `{$ident}` specified more than once
-/// .label = used more than once
-/// .label_previous_use = first use of `{$ident}`
-/// ```
-/// ...then the macro parse the Fluent resource, emitting a diagnostic if it fails to do so, and
-/// will generate the following code:
-///
-/// ```ignore (rust)
-/// pub static DEFAULT_LOCALE_RESOURCE: &'static [&'static str] = include_str!("./typeck.ftl");
-///
-/// mod fluent_generated {
-/// mod typeck {
-/// pub const field_multiply_specified_in_initializer: DiagnosticMessage =
-/// DiagnosticMessage::fluent("typeck_field_multiply_specified_in_initializer");
-/// pub const field_multiply_specified_in_initializer_label_previous_use: DiagnosticMessage =
-/// DiagnosticMessage::fluent_attr(
-/// "typeck_field_multiply_specified_in_initializer",
-/// "previous_use_label"
-/// );
-/// }
-/// }
-/// ```
-/// When emitting a diagnostic, the generated constants can be used as follows:
-///
-/// ```ignore (rust)
-/// let mut err = sess.struct_span_err(
-/// span,
-/// fluent::typeck::field_multiply_specified_in_initializer
-/// );
-/// err.span_default_label(span);
-/// err.span_label(
-/// previous_use_span,
-/// fluent::typeck::field_multiply_specified_in_initializer_label_previous_use
-/// );
-/// err.emit();
-/// ```
-#[proc_macro]
-pub fn fluent_messages(input: TokenStream) -> TokenStream {
- diagnostics::fluent_messages(input)
-}
-
decl_derive!([HashStable, attributes(stable_hasher)] => hash_stable::hash_stable_derive);
decl_derive!(
[HashStable_Generic, attributes(stable_hasher)] =>
diff --git a/compiler/rustc_macros/src/newtype.rs b/compiler/rustc_macros/src/newtype.rs
index 78a6f7488..415a89b0f 100644
--- a/compiler/rustc_macros/src/newtype.rs
+++ b/compiler/rustc_macros/src/newtype.rs
@@ -254,7 +254,7 @@ impl Parse for Newtype {
}
}
- impl rustc_index::vec::Idx for #name {
+ impl rustc_index::Idx for #name {
#[inline]
fn new(value: usize) -> Self {
Self::from_usize(value)
diff --git a/compiler/rustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs
index f85ba3800..d0d41c614 100644
--- a/compiler/rustc_macros/src/query.rs
+++ b/compiler/rustc_macros/src/query.rs
@@ -112,9 +112,6 @@ struct QueryModifiers {
/// Use a separate query provider for local and extern crates
separate_provide_extern: Option<Ident>,
- /// Always remap the ParamEnv's constness before hashing.
- remap_env_constness: Option<Ident>,
-
/// Generate a `feed` method to set the query's value from another query.
feedable: Option<Ident>,
}
@@ -130,7 +127,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
let mut eval_always = None;
let mut depth_limit = None;
let mut separate_provide_extern = None;
- let mut remap_env_constness = None;
let mut feedable = None;
while !input.is_empty() {
@@ -189,8 +185,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
try_insert!(depth_limit = modifier);
} else if modifier == "separate_provide_extern" {
try_insert!(separate_provide_extern = modifier);
- } else if modifier == "remap_env_constness" {
- try_insert!(remap_env_constness = modifier);
} else if modifier == "feedable" {
try_insert!(feedable = modifier);
} else {
@@ -211,7 +205,6 @@ fn parse_query_modifiers(input: ParseStream<'_>) -> Result<QueryModifiers> {
eval_always,
depth_limit,
separate_provide_extern,
- remap_env_constness,
feedable,
})
}
@@ -260,7 +253,7 @@ fn add_query_desc_cached_impl(
quote! {
#[allow(unused_variables, unused_braces, rustc::pass_by_value)]
#[inline]
- pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
+ pub fn #name<'tcx>(#tcx: TyCtxt<'tcx>, #key: &crate::query::queries::#name::Key<'tcx>) -> bool {
#expr
}
}
@@ -269,7 +262,7 @@ fn add_query_desc_cached_impl(
// we're taking `key` by reference, but some rustc types usually prefer being passed by value
#[allow(rustc::pass_by_value)]
#[inline]
- pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::ty::query::query_keys::#name<'tcx>) -> bool {
+ pub fn #name<'tcx>(_: TyCtxt<'tcx>, _: &crate::query::queries::#name::Key<'tcx>) -> bool {
false
}
}
@@ -280,7 +273,7 @@ fn add_query_desc_cached_impl(
let desc = quote! {
#[allow(unused_variables)]
- pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::ty::query::query_keys::#name<'tcx>) -> String {
+ pub fn #name<'tcx>(tcx: TyCtxt<'tcx>, key: crate::query::queries::#name::Key<'tcx>) -> String {
let (#tcx, #key) = (tcx, key);
::rustc_middle::ty::print::with_no_trimmed_paths!(
format!(#desc)
@@ -332,7 +325,6 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream {
eval_always,
depth_limit,
separate_provide_extern,
- remap_env_constness,
);
if modifiers.cache.is_some() {
diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml
index 4d7c133e0..840111c31 100644
--- a/compiler/rustc_metadata/Cargo.toml
+++ b/compiler/rustc_metadata/Cargo.toml
@@ -11,13 +11,13 @@ libloading = "0.7.1"
odht = { version = "0.3.1", features = ["nightly"] }
snap = "1"
tracing = "0.1"
-smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
tempfile = "3.2"
rustc_middle = { path = "../rustc_middle" }
rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_hir = { path = "../rustc_hir" }
rustc_hir_pretty = { path = "../rustc_hir_pretty" }
diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl
index 79b8b4172..6d8601b9e 100644
--- a/compiler/rustc_metadata/messages.ftl
+++ b/compiler/rustc_metadata/messages.ftl
@@ -1,288 +1,288 @@
-metadata_rlib_required =
- crate `{$crate_name}` required to be available in rlib format, but was not found in this form
-
-metadata_lib_required =
- crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+metadata_as_needed_compatibility =
+ linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
-metadata_rustc_lib_required =
- crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
- .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
- .help = try adding `extern crate rustc_driver;` at the top level of this crate
+metadata_bad_panic_strategy =
+ the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
-metadata_crate_dep_multiple =
- cannot satisfy dependencies so `{$crate_name}` only shows up once
- .help = having upstream crates all available in one format will likely make this go away
+metadata_bundle_needs_static =
+ linking modifier `bundle` is only compatible with `static` linking kind
-metadata_two_panic_runtimes =
- cannot link together two panic runtimes: {$prev_name} and {$cur_name}
+metadata_cannot_find_crate =
+ can't find crate for `{$crate_name}`{$add_info}
-metadata_bad_panic_strategy =
- the linked panic runtime `{$runtime}` is not compiled with this crate's panic strategy `{$strategy}`
+metadata_cant_find_crate =
+ can't find crate
-metadata_required_panic_strategy =
- the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+metadata_compiler_missing_profiler =
+ the compiler may have been built without the profiler runtime
-metadata_incompatible_panic_in_drop_strategy =
- the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+metadata_conflicting_alloc_error_handler =
+ the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
-metadata_multiple_names_in_link =
- multiple `name` arguments in a single `#[link]` attribute
+metadata_conflicting_global_alloc =
+ the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
-metadata_multiple_kinds_in_link =
- multiple `kind` arguments in a single `#[link]` attribute
+metadata_consider_building_std =
+ consider building the standard library from source with `cargo build -Zbuild-std`
-metadata_link_name_form =
- link name must be of the form `name = "string"`
+metadata_consider_downloading_target =
+ consider downloading the target with `rustup target add {$locator_triple}`
-metadata_link_kind_form =
- link kind must be of the form `kind = "string"`
+metadata_crate_dep_multiple =
+ cannot satisfy dependencies so `{$crate_name}` only shows up once
+ .help = having upstream crates all available in one format will likely make this go away
-metadata_link_modifiers_form =
- link modifiers must be of the form `modifiers = "string"`
+metadata_crate_location_unknown_type =
+ extern location for {$crate_name} is of an unknown type: {$path}
-metadata_link_cfg_form =
- link cfg must be of the form `cfg(/* predicate */)`
+metadata_crate_not_panic_runtime =
+ the crate `{$crate_name}` is not a panic runtime
-metadata_wasm_import_form =
- wasm import module must be of the form `wasm_import_module = "string"`
+metadata_dl_error =
+ {$err}
metadata_empty_link_name =
link name must not be empty
.label = empty link name
-metadata_link_framework_apple =
- link kind `framework` is only supported on Apple targets
+metadata_empty_renaming_target =
+ an empty renaming target was specified for library `{$lib_name}`
-metadata_framework_only_windows =
- link kind `raw-dylib` is only supported on Windows targets
+metadata_extern_location_not_exist =
+ extern location for {$crate_name} does not exist: {$location}
-metadata_unknown_link_kind =
- unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
- .label = unknown link kind
+metadata_extern_location_not_file =
+ extern location for {$crate_name} is not a file: {$location}
-metadata_multiple_link_modifiers =
- multiple `modifiers` arguments in a single `#[link]` attribute
+metadata_fail_create_file_encoder =
+ failed to create file encoder: {$err}
-metadata_multiple_cfgs =
- multiple `cfg` arguments in a single `#[link]` attribute
+metadata_fail_seek_file =
+ failed to seek the file: {$err}
-metadata_link_cfg_single_predicate =
- link cfg must have a single predicate argument
+metadata_fail_write_file =
+ failed to write to the file: {$err}
-metadata_multiple_wasm_import =
- multiple `wasm_import_module` arguments in a single `#[link]` attribute
+metadata_failed_create_encoded_metadata =
+ failed to create encoded metadata from file: {$err}
-metadata_unexpected_link_arg =
- unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
+metadata_failed_create_file =
+ failed to create the file {$filename}: {$err}
-metadata_invalid_link_modifier =
- invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
+metadata_failed_create_tempdir =
+ couldn't create a temp dir: {$err}
-metadata_multiple_modifiers =
- multiple `{$modifier}` modifiers in a single `modifiers` argument
+metadata_failed_write_error =
+ failed to write {$filename}: {$err}
-metadata_bundle_needs_static =
- linking modifier `bundle` is only compatible with `static` linking kind
+metadata_found_crate_versions =
+ the following crate versions were found:{$found_crates}
-metadata_whole_archive_needs_static =
- linking modifier `whole-archive` is only compatible with `static` linking kind
+metadata_found_staticlib =
+ found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
+ .help = please recompile that crate using --crate-type lib
-metadata_as_needed_compatibility =
- linking modifier `as-needed` is only compatible with `dylib` and `framework` linking kinds
+metadata_framework_only_windows =
+ link kind `raw-dylib` is only supported on Windows targets
-metadata_unknown_link_modifier =
- unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
+metadata_global_alloc_required =
+ no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+
+metadata_import_name_type_form =
+ import name type must be of the form `import_name_type = "string"`
+
+metadata_import_name_type_raw =
+ import name type can only be used with link kind `raw-dylib`
+
+metadata_import_name_type_x86 =
+ import name type is only supported on x86
+
+metadata_incompatible_panic_in_drop_strategy =
+ the crate `{$crate_name}` is compiled with the panic-in-drop strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
+
+metadata_incompatible_rustc =
+ found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
+ .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
metadata_incompatible_wasm_link =
`wasm_import_module` is incompatible with other arguments in `#[link]` attributes
-metadata_link_requires_name =
- `#[link]` attribute requires a `name = "string"` argument
- .label = missing `name` argument
+metadata_install_missing_components =
+ maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
-metadata_raw_dylib_no_nul =
- link name must not contain NUL characters if link kind is `raw-dylib`
+metadata_invalid_link_modifier =
+ invalid linking modifier syntax, expected '+' or '-' prefix before one of: bundle, verbatim, whole-archive, as-needed
-metadata_link_ordinal_raw_dylib =
- `#[link_ordinal]` is only supported if link kind is `raw-dylib`
+metadata_invalid_meta_files =
+ found invalid metadata files for crate `{$crate_name}`{$add_info}
+
+metadata_lib_filename_form =
+ file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix}
metadata_lib_framework_apple =
library kind `framework` is only supported on Apple targets
-metadata_empty_renaming_target =
- an empty renaming target was specified for library `{$lib_name}`
+metadata_lib_required =
+ crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
-metadata_renaming_no_link =
- renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
+metadata_link_cfg_form =
+ link cfg must be of the form `cfg(/* predicate */)`
-metadata_multiple_renamings =
- multiple renamings were specified for library `{$lib_name}`
+metadata_link_cfg_single_predicate =
+ link cfg must have a single predicate argument
-metadata_no_link_mod_override =
- overriding linking modifiers from command line is not supported
+metadata_link_framework_apple =
+ link kind `framework` is only supported on Apple targets
-metadata_unsupported_abi_i686 =
- ABI not supported by `#[link(kind = "raw-dylib")]` on i686
+metadata_link_kind_form =
+ link kind must be of the form `kind = "string"`
-metadata_unsupported_abi =
- ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
+metadata_link_modifiers_form =
+ link modifiers must be of the form `modifiers = "string"`
-metadata_fail_create_file_encoder =
- failed to create file encoder: {$err}
+metadata_link_name_form =
+ link name must be of the form `name = "string"`
-metadata_fail_seek_file =
- failed to seek the file: {$err}
+metadata_link_ordinal_raw_dylib =
+ `#[link_ordinal]` is only supported if link kind is `raw-dylib`
-metadata_fail_write_file =
- failed to write to the file: {$err}
+metadata_link_requires_name =
+ `#[link]` attribute requires a `name = "string"` argument
+ .label = missing `name` argument
-metadata_crate_not_panic_runtime =
- the crate `{$crate_name}` is not a panic runtime
+metadata_missing_native_library =
+ could not find native static library `{$libname}`, perhaps an -L flag is missing?
-metadata_no_panic_strategy =
- the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
+metadata_multiple_candidates =
+ multiple candidates for `{$flavor}` dependency `{$crate_name}` found
-metadata_profiler_builtins_needs_core =
- `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
+metadata_multiple_cfgs =
+ multiple `cfg` arguments in a single `#[link]` attribute
-metadata_not_profiler_runtime =
- the crate `{$crate_name}` is not a profiler runtime
+metadata_multiple_import_name_type =
+ multiple `import_name_type` arguments in a single `#[link]` attribute
-metadata_no_multiple_global_alloc =
- cannot define multiple global allocators
- .label = cannot define a new global allocator
+metadata_multiple_kinds_in_link =
+ multiple `kind` arguments in a single `#[link]` attribute
-metadata_prev_global_alloc =
- previous global allocator defined here
+metadata_multiple_link_modifiers =
+ multiple `modifiers` arguments in a single `#[link]` attribute
-metadata_no_multiple_alloc_error_handler =
- cannot define multiple allocation error handlers
- .label = cannot define a new allocation error handler
+metadata_multiple_modifiers =
+ multiple `{$modifier}` modifiers in a single `modifiers` argument
-metadata_prev_alloc_error_handler =
- previous allocation error handler defined here
+metadata_multiple_names_in_link =
+ multiple `name` arguments in a single `#[link]` attribute
-metadata_conflicting_global_alloc =
- the `#[global_allocator]` in {$other_crate_name} conflicts with global allocator in: {$crate_name}
+metadata_multiple_renamings =
+ multiple renamings were specified for library `{$lib_name}`
-metadata_conflicting_alloc_error_handler =
- the `#[alloc_error_handler]` in {$other_crate_name} conflicts with allocation error handler in: {$crate_name}
+metadata_multiple_wasm_import =
+ multiple `wasm_import_module` arguments in a single `#[link]` attribute
-metadata_global_alloc_required =
- no global memory allocator found but one is required; link to std or add `#[global_allocator]` to a static item that implements the GlobalAlloc trait
+metadata_newer_crate_version =
+ found possibly newer version of crate `{$crate_name}`{$add_info}
+ .note = perhaps that crate needs to be recompiled?
-metadata_no_transitive_needs_dep =
- the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
+metadata_no_crate_with_triple =
+ couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
-metadata_failed_write_error =
- failed to write {$filename}: {$err}
+metadata_no_dylib_plugin =
+ plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
-metadata_missing_native_library =
- could not find native static library `{$libname}`, perhaps an -L flag is missing?
+metadata_no_link_mod_override =
+ overriding linking modifiers from command line is not supported
-metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
+metadata_no_multiple_alloc_error_handler =
+ cannot define multiple allocation error handlers
+ .label = cannot define a new allocation error handler
-metadata_failed_create_tempdir =
- couldn't create a temp dir: {$err}
+metadata_no_multiple_global_alloc =
+ cannot define multiple global allocators
+ .label = cannot define a new global allocator
-metadata_failed_create_file =
- failed to create the file {$filename}: {$err}
+metadata_no_panic_strategy =
+ the crate `{$crate_name}` does not have the panic strategy `{$strategy}`
-metadata_failed_create_encoded_metadata =
- failed to create encoded metadata from file: {$err}
+metadata_no_transitive_needs_dep =
+ the crate `{$crate_name}` cannot depend on a crate that needs {$needs_crate_name}, but it depends on `{$deps_crate_name}`
metadata_non_ascii_name =
cannot load a crate with a non-ascii name `{$crate_name}`
-metadata_extern_location_not_exist =
- extern location for {$crate_name} does not exist: {$location}
-
-metadata_extern_location_not_file =
- extern location for {$crate_name} is not a file: {$location}
-
-metadata_multiple_candidates =
- multiple candidates for `{$flavor}` dependency `{$crate_name}` found
+metadata_not_profiler_runtime =
+ the crate `{$crate_name}` is not a profiler runtime
-metadata_symbol_conflicts_current =
- the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
+metadata_only_provide_library_name = only provide the library name `{$suggested_name}`, not the full filename
-metadata_symbol_conflicts_others =
- found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
+metadata_prev_alloc_error_handler =
+ previous allocation error handler defined here
-metadata_stable_crate_id_collision =
- found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
+metadata_prev_global_alloc =
+ previous global allocator defined here
-metadata_dl_error =
- {$err}
+metadata_profiler_builtins_needs_core =
+ `profiler_builtins` crate (required by compiler options) is not compatible with crate attribute `#![no_core]`
-metadata_newer_crate_version =
- found possibly newer version of crate `{$crate_name}`{$add_info}
- .note = perhaps that crate needs to be recompiled?
+metadata_raw_dylib_no_nul =
+ link name must not contain NUL characters if link kind is `raw-dylib`
-metadata_found_crate_versions =
- the following crate versions were found:{$found_crates}
+metadata_renaming_no_link =
+ renaming of the library `{$lib_name}` was specified, however this crate contains no `#[link(...)]` attributes referencing this library
-metadata_no_crate_with_triple =
- couldn't find crate `{$crate_name}` with expected target triple {$locator_triple}{$add_info}
+metadata_required_panic_strategy =
+ the crate `{$crate_name}` requires panic strategy `{$found_strategy}` which is incompatible with this crate's strategy of `{$desired_strategy}`
-metadata_found_staticlib =
- found staticlib `{$crate_name}` instead of rlib or dylib{$add_info}
- .help = please recompile that crate using --crate-type lib
+metadata_rlib_required =
+ crate `{$crate_name}` required to be available in rlib format, but was not found in this form
-metadata_incompatible_rustc =
- found crate `{$crate_name}` compiled by an incompatible version of rustc{$add_info}
- .help = please recompile that crate using this compiler ({$rustc_version}) (consider running `cargo clean` first)
+metadata_rustc_lib_required =
+ crate `{$crate_name}` required to be available in {$kind} format, but was not found in this form
+ .note = only .rmeta files are distributed for `rustc_private` crates other than `rustc_driver`
+ .help = try adding `extern crate rustc_driver;` at the top level of this crate
-metadata_invalid_meta_files =
- found invalid metadata files for crate `{$crate_name}`{$add_info}
+metadata_stable_crate_id_collision =
+ found crates (`{$crate_name0}` and `{$crate_name1}`) with colliding StableCrateId values.
-metadata_cannot_find_crate =
- can't find crate for `{$crate_name}`{$add_info}
+metadata_std_required =
+ `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
-metadata_no_dylib_plugin =
- plugin `{$crate_name}` only found in rlib format, but must be available in dylib format
+metadata_symbol_conflicts_current =
+ the current crate is indistinguishable from one of its dependencies: it has the same crate-name `{$crate_name}` and was compiled with the same `-C metadata` arguments. This will result in symbol conflicts between the two.
-metadata_target_not_installed =
- the `{$locator_triple}` target may not be installed
+metadata_symbol_conflicts_others =
+ found two different crates with name `{$crate_name}` that are not distinguished by differing `-C metadata`. This will result in symbol conflicts between the two.
metadata_target_no_std_support =
the `{$locator_triple}` target may not support the standard library
-metadata_consider_downloading_target =
- consider downloading the target with `rustup target add {$locator_triple}`
-
-metadata_std_required =
- `std` is required by `{$current_crate}` because it does not declare `#![no_std]`
-
-metadata_consider_building_std =
- consider building the standard library from source with `cargo build -Zbuild-std`
-
-metadata_compiler_missing_profiler =
- the compiler may have been built without the profiler runtime
+metadata_target_not_installed =
+ the `{$locator_triple}` target may not be installed
-metadata_install_missing_components =
- maybe you need to install the missing components with: `rustup component add rust-src rustc-dev llvm-tools-preview`
+metadata_two_panic_runtimes =
+ cannot link together two panic runtimes: {$prev_name} and {$cur_name}
-metadata_cant_find_crate =
- can't find crate
+metadata_unexpected_link_arg =
+ unexpected `#[link]` argument, expected one of: name, kind, modifiers, cfg, wasm_import_module, import_name_type
-metadata_crate_location_unknown_type =
- extern location for {$crate_name} is of an unknown type: {$path}
+metadata_unknown_import_name_type =
+ unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
-metadata_lib_filename_form =
- file name should be lib*.rlib or {$dll_prefix}*{$dll_suffix}
+metadata_unknown_link_kind =
+ unknown link kind `{$kind}`, expected one of: static, dylib, framework, raw-dylib
+ .label = unknown link kind
-metadata_multiple_import_name_type =
- multiple `import_name_type` arguments in a single `#[link]` attribute
+metadata_unknown_link_modifier =
+ unknown linking modifier `{$modifier}`, expected one of: bundle, verbatim, whole-archive, as-needed
-metadata_import_name_type_form =
- import name type must be of the form `import_name_type = "string"`
+metadata_unsupported_abi =
+ ABI not supported by `#[link(kind = "raw-dylib")]` on this architecture
-metadata_import_name_type_x86 =
- import name type is only supported on x86
+metadata_unsupported_abi_i686 =
+ ABI not supported by `#[link(kind = "raw-dylib")]` on i686
-metadata_unknown_import_name_type =
- unknown import name type `{$import_name_type}`, expected one of: decorated, noprefix, undecorated
+metadata_wasm_import_form =
+ wasm import module must be of the form `wasm_import_module = "string"`
-metadata_import_name_type_raw =
- import name type can only be used with link kind `raw-dylib`
+metadata_whole_archive_needs_static =
+ linking modifier `whole-archive` is only compatible with `static` linking kind
diff --git a/compiler/rustc_metadata/src/creader.rs b/compiler/rustc_metadata/src/creader.rs
index 23aceca06..aaf72ab94 100644
--- a/compiler/rustc_metadata/src/creader.rs
+++ b/compiler/rustc_metadata/src/creader.rs
@@ -4,7 +4,7 @@ use crate::errors;
use crate::locator::{CrateError, CrateLocator, CratePaths};
use crate::rmeta::{CrateDep, CrateMetadata, CrateNumMap, CrateRoot, MetadataBlob};
-use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_ast::expand::allocator::{alloc_error_handler_name, global_fn_name, AllocatorKind};
use rustc_ast::{self as ast, *};
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::svh::Svh;
@@ -12,7 +12,7 @@ use rustc_data_structures::sync::{MappedReadGuard, MappedWriteGuard, ReadGuard,
use rustc_expand::base::SyntaxExtension;
use rustc_hir::def_id::{CrateNum, LocalDefId, StableCrateId, StableCrateIdMap, LOCAL_CRATE};
use rustc_hir::definitions::Definitions;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{self, CrateType, ExternLocation};
use rustc_session::cstore::ExternCrateSource;
@@ -27,6 +27,7 @@ use rustc_span::{Span, DUMMY_SP};
use rustc_target::spec::{PanicStrategy, TargetTriple};
use proc_macro::bridge::client::ProcMacro;
+use std::error::Error;
use std::ops::Fn;
use std::path::Path;
use std::time::Duration;
@@ -147,11 +148,15 @@ impl CStore {
assert_eq!(self.metas.len(), self.stable_crate_ids.len());
let num = CrateNum::new(self.stable_crate_ids.len());
if let Some(&existing) = self.stable_crate_ids.get(&root.stable_crate_id()) {
- let crate_name0 = root.name();
- if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name()) {
+ // Check for (potential) conflicts with the local crate
+ if existing == LOCAL_CRATE {
+ Err(CrateError::SymbolConflictsCurrent(root.name()))
+ } else if let Some(crate_name1) = self.metas[existing].as_ref().map(|data| data.name())
+ {
+ let crate_name0 = root.name();
Err(CrateError::StableCrateIdCollision(crate_name0, crate_name1))
} else {
- Err(CrateError::SymbolConflictsCurrent(crate_name0))
+ Err(CrateError::NotFound(root.name()))
}
} else {
self.metas.push(None);
@@ -368,7 +373,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
let host_hash = host_lib.as_ref().map(|lib| lib.metadata.get_root().hash());
let private_dep =
- self.sess.opts.externs.get(name.as_str()).map_or(false, |e| e.is_private_dep);
+ self.sess.opts.externs.get(name.as_str()).is_some_and(|e| e.is_private_dep);
// Claim this crate number and cache it
let cnum = self.cstore.intern_stable_crate_id(&crate_root)?;
@@ -864,6 +869,17 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
}
+ fn inject_forced_externs(&mut self) {
+ for (name, entry) in self.sess.opts.externs.iter() {
+ if entry.force {
+ let name_interned = Symbol::intern(name);
+ if !self.used_extern_options.contains(&name_interned) {
+ self.resolve_crate(name_interned, DUMMY_SP, CrateDepKind::Explicit);
+ }
+ }
+ }
+ }
+
fn inject_dependency_if(
&self,
krate: CrateNum,
@@ -912,7 +928,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
// Don't worry about pathless `--extern foo` sysroot references
continue;
}
- if entry.nounused_dep {
+ if entry.nounused_dep || entry.force {
// We're not worried about this one
continue;
}
@@ -931,7 +947,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
lint::builtin::UNUSED_CRATE_DEPENDENCIES,
span,
ast::CRATE_NODE_ID,
- &format!(
+ format!(
"external crate `{}` unused in `{}`: remove the dependency or add `use {} as _;`",
name,
self.tcx.crate_name(LOCAL_CRATE),
@@ -941,6 +957,7 @@ impl<'a, 'tcx> CrateLoader<'a, 'tcx> {
}
pub fn postprocess(&mut self, krate: &ast::Crate) {
+ self.inject_forced_externs();
self.inject_profiler_runtime(krate);
self.inject_allocator_crate(krate);
self.inject_panic_runtime(krate);
@@ -1031,7 +1048,7 @@ fn global_allocator_spans(krate: &ast::Crate) -> Vec<Span> {
}
}
- let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::alloc));
+ let name = Symbol::intern(&global_fn_name(sym::alloc));
let mut f = Finder { name, spans: Vec::new() };
visit::walk_crate(&mut f, krate);
f.spans
@@ -1053,7 +1070,7 @@ fn alloc_error_handler_spans(krate: &ast::Crate) -> Vec<Span> {
}
}
- let name = Symbol::intern(&AllocatorKind::Global.fn_name(sym::oom));
+ let name = Symbol::intern(alloc_error_handler_name(AllocatorKind::Global));
let mut f = Finder { name, spans: Vec::new() };
visit::walk_crate(&mut f, krate);
f.spans
@@ -1094,5 +1111,12 @@ fn load_dylib(path: &Path, max_attempts: usize) -> Result<libloading::Library, S
}
debug!("Failed to load proc-macro `{}` even after {} attempts.", path.display(), max_attempts);
- Err(format!("{} (retried {} times)", last_error.unwrap(), max_attempts))
+
+ let last_error = last_error.unwrap();
+ let message = if let Some(src) = last_error.source() {
+ format!("{last_error} ({src}) (retried {max_attempts} times)")
+ } else {
+ format!("{last_error} (retried {max_attempts} times)")
+ };
+ Err(message)
}
diff --git a/compiler/rustc_metadata/src/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs
index 39ef4276f..72b208a71 100644
--- a/compiler/rustc_metadata/src/dependency_format.rs
+++ b/compiler/rustc_metadata/src/dependency_format.rs
@@ -89,11 +89,25 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
// to try to eagerly statically link all dependencies. This is normally
// done for end-product dylibs, not intermediate products.
//
- // Treat cdylibs similarly. If `-C prefer-dynamic` is set, the caller may
- // be code-size conscious, but without it, it makes sense to statically
- // link a cdylib.
- CrateType::Dylib | CrateType::Cdylib if !sess.opts.cg.prefer_dynamic => Linkage::Static,
- CrateType::Dylib | CrateType::Cdylib => Linkage::Dynamic,
+ // Treat cdylibs and staticlibs similarly. If `-C prefer-dynamic` is set,
+ // the caller may be code-size conscious, but without it, it makes sense
+ // to statically link a cdylib or staticlib. For staticlibs we use
+ // `-Z staticlib-prefer-dynamic` for now. This may be merged into
+ // `-C prefer-dynamic` in the future.
+ CrateType::Dylib | CrateType::Cdylib => {
+ if sess.opts.cg.prefer_dynamic {
+ Linkage::Dynamic
+ } else {
+ Linkage::Static
+ }
+ }
+ CrateType::Staticlib => {
+ if sess.opts.unstable_opts.staticlib_prefer_dynamic {
+ Linkage::Dynamic
+ } else {
+ Linkage::Static
+ }
+ }
// If the global prefer_dynamic switch is turned off, or the final
// executable will be statically linked, prefer static crate linkage.
@@ -108,9 +122,6 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
// No linkage happens with rlibs, we just needed the metadata (which we
// got long ago), so don't bother with anything.
CrateType::Rlib => Linkage::NotLinked,
-
- // staticlibs must have all static dependencies.
- CrateType::Staticlib => Linkage::Static,
};
match preferred_linkage {
@@ -123,9 +134,9 @@ fn calculate_type(tcx: TyCtxt<'_>, ty: CrateType) -> DependencyList {
return v;
}
- // Staticlibs and static executables must have all static dependencies.
+ // Static executables must have all static dependencies.
// If any are not found, generate some nice pretty errors.
- if ty == CrateType::Staticlib
+ if (ty == CrateType::Staticlib && !sess.opts.unstable_opts.staticlib_allow_rdylib_deps)
|| (ty == CrateType::Executable
&& sess.crt_static(Some(ty))
&& !sess.target.crt_static_allows_dylibs)
diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs
index 51b41b5f6..a44c1dd58 100644
--- a/compiler/rustc_metadata/src/errors.rs
+++ b/compiler/rustc_metadata/src/errors.rs
@@ -498,7 +498,7 @@ impl IntoDiagnostic<'_> for MultipleCandidates {
diag.code(error_code!(E0464));
diag.set_span(self.span);
for (i, candidate) in self.candidates.iter().enumerate() {
- diag.note(&format!("candidate #{}: {}", i + 1, candidate.display()));
+ diag.note(format!("candidate #{}: {}", i + 1, candidate.display()));
}
diag
}
diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs
index 81e62eccb..9f664d0f0 100644
--- a/compiler/rustc_metadata/src/lib.rs
+++ b/compiler/rustc_metadata/src/lib.rs
@@ -28,7 +28,7 @@ extern crate tracing;
pub use rmeta::{provide, provide_extern};
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
mod dependency_format;
mod foreign_modules;
diff --git a/compiler/rustc_metadata/src/locator.rs b/compiler/rustc_metadata/src/locator.rs
index c6af8d632..ceb348f34 100644
--- a/compiler/rustc_metadata/src/locator.rs
+++ b/compiler/rustc_metadata/src/locator.rs
@@ -220,7 +220,6 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::owned_slice::slice_owned;
use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::MetadataRef;
use rustc_errors::{DiagnosticArgValue, FatalError, IntoDiagnosticArg};
use rustc_fs_util::try_canonicalize;
use rustc_session::config::{self, CrateType};
@@ -246,6 +245,7 @@ pub(crate) struct CrateLocator<'a> {
only_needs_metadata: bool,
sysroot: &'a Path,
metadata_loader: &'a dyn MetadataLoader,
+ cfg_version: &'static str,
// Immutable per-search configuration.
crate_name: Symbol,
@@ -323,6 +323,7 @@ impl<'a> CrateLocator<'a> {
only_needs_metadata,
sysroot: &sess.sysroot,
metadata_loader,
+ cfg_version: sess.cfg_version,
crate_name,
exact_paths: if hash.is_none() {
sess.opts
@@ -566,7 +567,7 @@ impl<'a> CrateLocator<'a> {
let mut err_data: Option<Vec<PathBuf>> = None;
for (lib, kind) in m {
info!("{} reading metadata from: {}", flavor, lib.display());
- if flavor == CrateFlavor::Rmeta && lib.metadata().map_or(false, |m| m.len() == 0) {
+ if flavor == CrateFlavor::Rmeta && lib.metadata().is_ok_and(|m| m.len() == 0) {
// Empty files will cause get_metadata_section to fail. Rmeta
// files can be empty, for example with binaries (which can
// often appear with `cargo check` when checking a library as
@@ -601,7 +602,7 @@ impl<'a> CrateLocator<'a> {
}
};
// If we see multiple hashes, emit an error about duplicate candidates.
- if slot.as_ref().map_or(false, |s| s.0 != hash) {
+ if slot.as_ref().is_some_and(|s| s.0 != hash) {
if let Some(candidates) = err_data {
return Err(CrateError::MultipleCandidates(
self.crate_name,
@@ -655,7 +656,7 @@ impl<'a> CrateLocator<'a> {
}
fn crate_matches(&mut self, metadata: &MetadataBlob, libpath: &Path) -> Option<Svh> {
- let rustc_version = rustc_version();
+ let rustc_version = rustc_version(self.cfg_version);
let found_version = metadata.get_rustc_version();
if found_version != rustc_version {
info!("Rejecting via version: expected {} got {}", rustc_version, found_version);
@@ -782,7 +783,7 @@ fn get_metadata_section<'p>(
if !filename.exists() {
return Err(MetadataError::NotPresent(filename));
}
- let raw_bytes: MetadataRef = match flavor {
+ let raw_bytes = match flavor {
CrateFlavor::Rlib => {
loader.get_rlib_metadata(target, filename).map_err(MetadataError::LoadFailure)?
}
@@ -843,7 +844,7 @@ fn get_metadata_section<'p>(
slice_owned(mmap, Deref::deref)
}
};
- let blob = MetadataBlob::new(raw_bytes);
+ let blob = MetadataBlob(raw_bytes);
if blob.is_compatible() {
Ok(blob)
} else {
@@ -960,6 +961,7 @@ pub(crate) enum CrateError {
DlSym(String),
LocatorCombined(Box<CombinedLocatorError>),
NonDylibPlugin(Symbol),
+ NotFound(Symbol),
}
enum MetadataError<'a> {
@@ -1097,7 +1099,7 @@ impl CrateError {
crate_name,
add_info,
found_crates,
- rustc_version: rustc_version(),
+ rustc_version: rustc_version(sess.cfg_version),
});
} else if !locator.crate_rejections.via_invalid.is_empty() {
let mut crate_rejections = Vec::new();
@@ -1130,6 +1132,18 @@ impl CrateError {
CrateError::NonDylibPlugin(crate_name) => {
sess.emit_err(errors::NoDylibPlugin { span, crate_name });
}
+ CrateError::NotFound(crate_name) => {
+ sess.emit_err(errors::CannotFindCrate {
+ span,
+ crate_name,
+ add_info: String::new(),
+ missing_core,
+ current_crate: sess.opts.crate_name.clone().unwrap_or("<unknown>".to_string()),
+ is_nightly_build: sess.is_nightly_build(),
+ profiler_runtime: Symbol::intern(&sess.opts.unstable_opts.profiler_runtime),
+ locator_triple: sess.opts.target_triple.clone(),
+ });
+ }
}
}
}
diff --git a/compiler/rustc_metadata/src/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs
index b855c8e43..c83c47e72 100644
--- a/compiler/rustc_metadata/src/native_libs.rs
+++ b/compiler/rustc_metadata/src/native_libs.rs
@@ -161,14 +161,6 @@ impl<'tcx> Collector<'tcx> {
"raw-dylib" => {
if !sess.target.is_like_windows {
sess.emit_err(errors::FrameworkOnlyWindows { span });
- } else if !features.raw_dylib && sess.target.arch == "x86" {
- feature_err(
- &sess.parse_sess,
- sym::raw_dylib,
- span,
- "link kind `raw-dylib` is unstable on x86",
- )
- .emit();
}
NativeLibKind::RawDylib
}
@@ -251,16 +243,6 @@ impl<'tcx> Collector<'tcx> {
continue;
}
};
- if !features.raw_dylib {
- let span = item.name_value_literal_span().unwrap();
- feature_err(
- &sess.parse_sess,
- sym::raw_dylib,
- span,
- "import name type is unstable",
- )
- .emit();
- }
import_name_type = Some((link_import_name_type, item.span()));
}
_ => {
@@ -287,7 +269,7 @@ impl<'tcx> Collector<'tcx> {
&sess.parse_sess,
sym::$feature,
span,
- &format!("linking modifier `{modifier}` is unstable"),
+ format!("linking modifier `{modifier}` is unstable"),
)
.emit();
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs
index 9f41dc92f..cc4e60cf6 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder.rs
@@ -7,6 +7,7 @@ use crate::rmeta::*;
use rustc_ast as ast;
use rustc_data_structures::captures::Captures;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::owned_slice::OwnedSlice;
use rustc_data_structures::svh::Svh;
use rustc_data_structures::sync::{AppendOnlyVec, Lock, Lrc, OnceCell};
use rustc_data_structures::unhash::UnhashMap;
@@ -16,14 +17,15 @@ use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, CRATE_DEF_INDEX, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc_hir::diagnostic_items::DiagnosticItems;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::metadata::ModChild;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::ty::codec::TyDecoder;
use rustc_middle::ty::fast_reject::SimplifiedType;
use rustc_middle::ty::GeneratorDiagnosticData;
-use rustc_middle::ty::{self, ParameterizedOverTcx, Ty, TyCtxt, Visibility};
+use rustc_middle::ty::{self, ParameterizedOverTcx, Predicate, Ty, TyCtxt, Visibility};
use rustc_serialize::opaque::MemDecoder;
use rustc_serialize::{Decodable, Decoder};
use rustc_session::cstore::{
@@ -50,7 +52,7 @@ mod cstore_impl;
/// A `MetadataBlob` internally is just a reference counted pointer to
/// the actual data, so cloning it is cheap.
#[derive(Clone)]
-pub(crate) struct MetadataBlob(Lrc<MetadataRef>);
+pub(crate) struct MetadataBlob(pub(crate) OwnedSlice);
impl std::ops::Deref for MetadataBlob {
type Target = [u8];
@@ -117,7 +119,7 @@ pub(crate) struct CrateMetadata {
/// Additional data used for decoding `HygieneData` (e.g. `SyntaxContext`
/// and `ExpnId`).
- /// Note that we store a `HygieneDecodeContext` for each `CrateMetadat`. This is
+ /// Note that we store a `HygieneDecodeContext` for each `CrateMetadata`. This is
/// because `SyntaxContext` ids are not globally unique, so we need
/// to track which ids we've decoded on a per-crate basis.
hygiene_context: HygieneDecodeContext,
@@ -373,16 +375,6 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
self.tcx()
}
- #[inline]
- fn peek_byte(&self) -> u8 {
- self.opaque.data[self.opaque.position()]
- }
-
- #[inline]
- fn position(&self) -> usize {
- self.opaque.position()
- }
-
fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
F: FnOnce(&mut Self) -> Ty<'tcx>,
@@ -404,7 +396,7 @@ impl<'a, 'tcx> TyDecoder for DecodeContext<'a, 'tcx> {
where
F: FnOnce(&mut Self) -> R,
{
- let new_opaque = MemDecoder::new(self.opaque.data, pos);
+ let new_opaque = MemDecoder::new(self.opaque.data(), pos);
let old_opaque = mem::replace(&mut self.opaque, new_opaque);
let old_state = mem::replace(&mut self.lazy_state, LazyState::NoNode);
let r = f(self);
@@ -625,17 +617,12 @@ impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for Symbol {
SYMBOL_OFFSET => {
// read str offset
let pos = d.read_usize();
- let old_pos = d.opaque.position();
-
- // move to str ofset and read
- d.opaque.set_position(pos);
- let s = d.read_str();
- let sym = Symbol::intern(s);
-
- // restore position
- d.opaque.set_position(old_pos);
- sym
+ // move to str offset and read
+ d.opaque.with_position(pos, |d| {
+ let s = d.read_str();
+ Symbol::intern(s)
+ })
}
SYMBOL_PREINTERNED => {
let symbol_index = d.read_u32();
@@ -675,10 +662,6 @@ impl<'a, 'tcx, I: Idx, T> Decodable<DecodeContext<'a, 'tcx>> for LazyTable<I, T>
implement_ty_decoder!(DecodeContext<'a, 'tcx>);
impl MetadataBlob {
- pub(crate) fn new(metadata_ref: MetadataRef) -> MetadataBlob {
- MetadataBlob(Lrc::new(metadata_ref))
- }
-
pub(crate) fn is_compatible(&self) -> bool {
self.blob().starts_with(METADATA_HEADER)
}
@@ -857,6 +840,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
)
}
+ fn get_explicit_item_bounds(
+ self,
+ index: DefIndex,
+ tcx: TyCtxt<'tcx>,
+ ) -> ty::EarlyBinder<&'tcx [(Predicate<'tcx>, Span)]> {
+ let lazy = self.root.tables.explicit_item_bounds.get(self, index);
+ let output = if lazy.is_default() {
+ &mut []
+ } else {
+ tcx.arena.alloc_from_iter(lazy.decode((self, tcx)))
+ };
+ ty::EarlyBinder(&*output)
+ }
+
fn get_variant(
self,
kind: DefKind,
@@ -883,16 +880,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
variant_did,
ctor,
data.discr,
- self.root
- .tables
- .children
- .get(self, index)
- .expect("fields are not encoded for a variant")
- .decode(self)
- .map(|index| ty::FieldDef {
- did: self.local_def_id(index),
- name: self.item_name(index),
- vis: self.get_visibility(index),
+ self.get_associated_item_or_field_def_ids(index)
+ .map(|did| ty::FieldDef {
+ did,
+ name: self.item_name(did.index),
+ vis: self.get_visibility(did.index),
})
.collect(),
adt_kind,
@@ -918,7 +910,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
let mut variants: Vec<_> = if let ty::AdtKind::Enum = adt_kind {
self.root
.tables
- .children
+ .module_children_non_reexports
.get(self, item_id)
.expect("variants are not encoded for an enum")
.decode(self)
@@ -967,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.decode((self, sess))
}
- fn get_debugger_visualizers(self) -> Vec<rustc_span::DebuggerVisualizerFile> {
+ fn get_debugger_visualizers(self) -> Vec<DebuggerVisualizerFile> {
self.root.debugger_visualizers.decode(self).collect::<Vec<_>>()
}
@@ -1013,9 +1005,8 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
let ident = self.item_ident(id, sess);
let res = Res::Def(self.def_kind(id), self.local_def_id(id));
let vis = self.get_visibility(id);
- let span = self.get_span(id, sess);
- ModChild { ident, res, vis, span, reexport_chain: Default::default() }
+ ModChild { ident, res, vis, reexport_chain: Default::default() }
}
/// Iterates over all named children of the given module,
@@ -1038,11 +1029,9 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
} else {
// Iterate over all children.
- for child_index in self.root.tables.children.get(self, id).unwrap().decode(self) {
- // FIXME: Do not encode RPITITs as a part of this list.
- if self.root.tables.opt_rpitit_info.get(self, child_index).is_none() {
- yield self.get_mod_child(child_index, sess);
- }
+ let non_reexports = self.root.tables.module_children_non_reexports.get(self, id);
+ for child_index in non_reexports.unwrap().decode(self) {
+ yield self.get_mod_child(child_index, sess);
}
let reexports = self.root.tables.module_children_reexports.get(self, id);
@@ -1071,20 +1060,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
.expect("argument names not encoded for a function")
.decode((self, sess))
.nth(0)
- .map_or(false, |ident| ident.name == kw::SelfLower)
+ .is_some_and(|ident| ident.name == kw::SelfLower)
}
- fn get_associated_item_def_ids(
+ fn get_associated_item_or_field_def_ids(
self,
id: DefIndex,
- sess: &'a Session,
) -> impl Iterator<Item = DefId> + 'a {
self.root
.tables
- .children
+ .associated_item_or_field_def_ids
.get(self, id)
- .expect("associated items not encoded for an item")
- .decode((self, sess))
+ .unwrap_or_else(|| self.missing("associated_item_or_field_def_ids", id))
+ .decode(self)
.map(move |child_index| self.local_def_id(child_index))
}
@@ -1264,14 +1252,6 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
}
}
- fn is_foreign_item(self, id: DefIndex) -> bool {
- if let Some(parent) = self.def_key(id).parent {
- matches!(self.def_kind(parent), DefKind::ForeignMod)
- } else {
- false
- }
- }
-
#[inline]
fn def_key(self, index: DefIndex) -> DefKey {
*self
@@ -1482,28 +1462,30 @@ impl<'a, 'tcx> CrateMetadataRef<'a> {
..
} = source_file_to_import;
- // If this file is under $sysroot/lib/rustlib/src/ but has not been remapped
- // during rust bootstrapping by `remap-debuginfo = true`, and the user
- // wish to simulate that behaviour by -Z simulate-remapped-rust-src-base,
+ // If this file is under $sysroot/lib/rustlib/src/
+ // and the user wish to simulate remapping with -Z simulate-remapped-rust-src-base,
// then we change `name` to a similar state as if the rust was bootstrapped
// with `remap-debuginfo = true`.
// This is useful for testing so that tests about the effects of
// `try_to_translate_virtual_to_real` don't have to worry about how the
// compiler is bootstrapped.
if let Some(virtual_dir) = &sess.opts.unstable_opts.simulate_remapped_rust_src_base
- {
- if let Some(real_dir) = &sess.opts.real_rust_source_base_dir {
- for subdir in ["library", "compiler"] {
- if let rustc_span::FileName::Real(ref mut old_name) = name {
- if let rustc_span::RealFileName::LocalPath(local) = old_name {
- if let Ok(rest) = local.strip_prefix(real_dir.join(subdir)) {
- *old_name = rustc_span::RealFileName::Remapped {
- local_path: None,
- virtual_name: virtual_dir.join(subdir).join(rest),
- };
- }
- }
- }
+ && let Some(real_dir) = &sess.opts.real_rust_source_base_dir
+ && let rustc_span::FileName::Real(ref mut old_name) = name {
+ let relative_path = match old_name {
+ rustc_span::RealFileName::LocalPath(local) => local.strip_prefix(real_dir).ok(),
+ rustc_span::RealFileName::Remapped { virtual_name, .. } => {
+ option_env!("CFG_VIRTUAL_RUST_SOURCE_BASE_DIR").and_then(|virtual_dir| virtual_name.strip_prefix(virtual_dir).ok())
+ }
+ };
+ debug!(?relative_path, ?virtual_dir, "simulate_remapped_rust_src_base");
+ for subdir in ["library", "compiler"] {
+ if let Some(rest) = relative_path.and_then(|p| p.strip_prefix(subdir).ok()) {
+ *old_name = rustc_span::RealFileName::Remapped {
+ local_path: None, // FIXME: maybe we should preserve this?
+ virtual_name: virtual_dir.join(subdir).join(rest),
+ };
+ break;
}
}
}
diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
index 31798afb8..7425963d3 100644
--- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
+++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs
@@ -14,8 +14,8 @@ use rustc_middle::metadata::ModChild;
use rustc_middle::middle::exported_symbols::ExportedSymbol;
use rustc_middle::middle::stability::DeprecationEntry;
use rustc_middle::query::LocalCrate;
+use rustc_middle::query::{ExternProviders, Providers};
use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::query::{ExternProviders, Providers};
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::cstore::CrateStore;
use rustc_session::{Session, StableCrateId};
@@ -114,8 +114,8 @@ macro_rules! provide_one {
($tcx:ident, $def_id:ident, $other:ident, $cdata:ident, $name:ident => $compute:block) => {
fn $name<'tcx>(
$tcx: TyCtxt<'tcx>,
- def_id_arg: ty::query::query_keys::$name<'tcx>,
- ) -> ty::query::query_provided::$name<'tcx> {
+ def_id_arg: rustc_middle::query::queries::$name::Key<'tcx>,
+ ) -> rustc_middle::query::queries::$name::ProvidedValue<'tcx> {
let _prof_timer =
$tcx.prof.generic_activity(concat!("metadata_decode_entry_", stringify!($name)));
@@ -203,7 +203,7 @@ impl IntoArgs for (CrateNum, SimplifiedType) {
}
provide! { tcx, def_id, other, cdata,
- explicit_item_bounds => { table_defaulted_array }
+ explicit_item_bounds => { cdata.get_explicit_item_bounds(def_id.index, tcx) }
explicit_predicates_of => { table }
generics_of => { table }
inferred_outlives_of => { table_defaulted_array }
@@ -276,11 +276,10 @@ provide! { tcx, def_id, other, cdata,
tcx.calculate_dtor(def_id, |_,_| Ok(()))
}
associated_item_def_ids => {
- tcx.arena.alloc_from_iter(cdata.get_associated_item_def_ids(def_id.index, tcx.sess))
+ tcx.arena.alloc_from_iter(cdata.get_associated_item_or_field_def_ids(def_id.index))
}
associated_item => { cdata.get_associated_item(def_id.index, tcx.sess) }
inherent_impls => { cdata.get_inherent_implementations_for_type(tcx, def_id.index) }
- is_foreign_item => { cdata.is_foreign_item(def_id.index) }
item_attrs => { tcx.arena.alloc_from_iter(cdata.get_item_attrs(def_id.index, tcx.sess)) }
is_mir_available => { cdata.is_item_mir_available(def_id.index) }
is_ctfe_mir_available => { cdata.is_ctfe_mir_available(def_id.index) }
@@ -324,7 +323,7 @@ provide! { tcx, def_id, other, cdata,
extra_filename => { cdata.root.extra_filename.clone() }
- traits_in_crate => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
+ traits => { tcx.arena.alloc_from_iter(cdata.get_traits()) }
trait_impls_in_crate => { tcx.arena.alloc_from_iter(cdata.get_trait_impls()) }
implementations_of_trait => { cdata.get_implementations_of_trait(tcx, other) }
crate_incoherent_impls => { cdata.get_incoherent_impls(tcx, other) }
@@ -516,14 +515,6 @@ impl CStore {
self.get_crate_data(def.krate).get_ctor(def.index)
}
- pub fn module_children_untracked<'a>(
- &'a self,
- def_id: DefId,
- sess: &'a Session,
- ) -> impl Iterator<Item = ModChild> + 'a {
- self.get_crate_data(def_id.krate).get_module_children(def_id.index, sess)
- }
-
pub fn load_macro_untracked(&self, id: DefId, sess: &Session) -> LoadedMacro {
let _prof_timer = sess.prof.generic_activity("metadata_load_macro");
diff --git a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
index 02cab561b..4f280bb9d 100644
--- a/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
+++ b/compiler/rustc_metadata/src/rmeta/def_path_hash_map.rs
@@ -1,6 +1,5 @@
use crate::rmeta::DecodeContext;
use crate::rmeta::EncodeContext;
-use rustc_data_structures::owned_slice::slice_owned;
use rustc_data_structures::owned_slice::OwnedSlice;
use rustc_hir::def_path_hash_map::{Config as HashMapConfig, DefPathHashMap};
use rustc_middle::parameterized_over_tcx;
@@ -45,12 +44,9 @@ impl<'a, 'tcx> Encodable<EncodeContext<'a, 'tcx>> for DefPathHashMapRef<'tcx> {
impl<'a, 'tcx> Decodable<DecodeContext<'a, 'tcx>> for DefPathHashMapRef<'static> {
fn decode(d: &mut DecodeContext<'a, 'tcx>) -> DefPathHashMapRef<'static> {
- // Import TyDecoder so we can access the DecodeContext::position() method
- use crate::rustc_middle::ty::codec::TyDecoder;
-
let len = d.read_usize();
let pos = d.position();
- let o = slice_owned(d.blob().clone(), |blob| &blob[pos..pos + len]);
+ let o = d.blob().clone().0.slice(|blob| &blob[pos..pos + len]);
// Although we already have the data we need via the `OwnedSlice`, we still need
// to advance the `DecodeContext`'s position so it's in a valid state after
diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs
index e44b133a9..f067bca4b 100644
--- a/compiler/rustc_metadata/src/rmeta/encoder.rs
+++ b/compiler/rustc_metadata/src/rmeta/encoder.rs
@@ -7,8 +7,8 @@ use rustc_ast::Attribute;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::{Mmap, MmapMut};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{join, par_iter, Lrc, ParallelIterator};
+use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
+use rustc_data_structures::sync::{join, par_for_each_in, Lrc};
use rustc_data_structures::temp_dir::MaybeTempDir;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
@@ -19,16 +19,17 @@ use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::lang_items::LangItem;
use rustc_middle::hir::nested_filter;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use rustc_middle::middle::dependency_format::Linkage;
use rustc_middle::middle::exported_symbols::{
metadata_symbol_name, ExportedSymbol, SymbolExportInfo,
};
use rustc_middle::mir::interpret;
use rustc_middle::query::LocalCrate;
+use rustc_middle::query::Providers;
use rustc_middle::traits::specialization_graph;
use rustc_middle::ty::codec::TyEncoder;
use rustc_middle::ty::fast_reject::{self, SimplifiedType, TreatParams};
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, SymbolName, Ty, TyCtxt};
use rustc_middle::util::common::to_readable_str;
use rustc_serialize::{opaque, Decodable, Decoder, Encodable, Encoder};
@@ -36,9 +37,7 @@ use rustc_session::config::{CrateType, OptLevel};
use rustc_session::cstore::{ForeignModule, LinkagePreference, NativeLib};
use rustc_span::hygiene::{ExpnIndex, HygieneEncodeContext, MacroKind};
use rustc_span::symbol::{sym, Symbol};
-use rustc_span::{
- self, DebuggerVisualizerFile, ExternalSource, FileName, SourceFile, Span, SyntaxContext,
-};
+use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SyntaxContext};
use std::borrow::Borrow;
use std::collections::hash_map::Entry;
use std::hash::Hash;
@@ -108,11 +107,7 @@ impl<'a, 'tcx> Encoder for EncodeContext<'a, 'tcx> {
emit_i64(i64);
emit_i32(i32);
emit_i16(i16);
- emit_i8(i8);
- emit_bool(bool);
- emit_char(char);
- emit_str(&str);
emit_raw_bytes(&[u8]);
}
}
@@ -531,7 +526,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
adapted.name_hash = {
let mut hasher: StableHasher = StableHasher::new();
adapted.name.hash(&mut hasher);
- hasher.finish::<u128>()
+ hasher.finish::<Hash128>()
};
Lrc::new(adapted)
} else {
@@ -832,18 +827,17 @@ fn should_encode_span(def_kind: DefKind) -> bool {
| DefKind::AssocFn
| DefKind::AssocConst
| DefKind::Macro(_)
+ | DefKind::ExternCrate
+ | DefKind::Use
| DefKind::AnonConst
| DefKind::InlineConst
| DefKind::OpaqueTy
+ | DefKind::ImplTraitPlaceholder
| DefKind::Field
| DefKind::Impl { .. }
| DefKind::Closure
| DefKind::Generator => true,
- DefKind::ExternCrate
- | DefKind::Use
- | DefKind::ForeignMod
- | DefKind::ImplTraitPlaceholder
- | DefKind::GlobalAsm => false,
+ DefKind::ForeignMod | DefKind::GlobalAsm => false,
}
}
@@ -867,6 +861,11 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
| DefKind::Macro(_)
| DefKind::Field
| DefKind::Impl { .. } => true,
+ // Tools may want to be able to detect their tool lints on
+ // closures from upstream crates, too. This is used by
+ // https://github.com/model-checking/kani and is not a performance
+ // or maintenance issue for us.
+ DefKind::Closure => true,
DefKind::TyParam
| DefKind::ConstParam
| DefKind::Ctor(..)
@@ -879,7 +878,6 @@ fn should_encode_attrs(def_kind: DefKind) -> bool {
| DefKind::ImplTraitPlaceholder
| DefKind::LifetimeParam
| DefKind::GlobalAsm
- | DefKind::Closure
| DefKind::Generator => false,
}
}
@@ -1366,9 +1364,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.params_in_repr[def_id] <- params_in_repr);
if adt_def.is_enum() {
- let module_children = tcx.module_children_non_reexports(local_def_id);
- record_array!(self.tables.children[def_id] <-
- module_children.iter().map(|def_id| def_id.local_def_index));
+ let module_children = tcx.module_children_local(local_def_id);
+ record_array!(self.tables.module_children_non_reexports[def_id] <-
+ module_children.iter().map(|child| child.res.def_id().index));
} else {
// For non-enum, there is only one variant, and its def_id is the adt's.
debug_assert_eq!(adt_def.variants().len(), 1);
@@ -1386,7 +1384,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
record!(self.tables.variant_data[variant.def_id] <- data);
self.tables.constness.set_some(variant.def_id.index, hir::Constness::Const);
- record_array!(self.tables.children[variant.def_id] <- variant.fields.iter().map(|f| {
+ record_array!(self.tables.associated_item_or_field_def_ids[variant.def_id] <- variant.fields.iter().map(|f| {
assert!(f.did.is_local());
f.did.index
}));
@@ -1415,18 +1413,20 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
// Encode this here because we don't do it in encode_def_ids.
record!(self.tables.expn_that_defined[def_id] <- tcx.expn_that_defined(local_def_id));
} else {
- let non_reexports = tcx.module_children_non_reexports(local_def_id);
- record_array!(self.tables.children[def_id] <-
- non_reexports.iter().map(|def_id| def_id.local_def_index));
+ let module_children = tcx.module_children_local(local_def_id);
+
+ record_array!(self.tables.module_children_non_reexports[def_id] <-
+ module_children.iter().filter(|child| child.reexport_chain.is_empty())
+ .map(|child| child.res.def_id().index));
record_defaulted_array!(self.tables.module_children_reexports[def_id] <-
- tcx.module_children_reexports(local_def_id));
+ module_children.iter().filter(|child| !child.reexport_chain.is_empty()));
}
}
fn encode_explicit_item_bounds(&mut self, def_id: DefId) {
debug!("EncodeContext::encode_explicit_item_bounds({:?})", def_id);
- let bounds = self.tcx.explicit_item_bounds(def_id);
+ let bounds = self.tcx.explicit_item_bounds(def_id).skip_binder();
record_defaulted_array!(self.tables.explicit_item_bounds[def_id] <- bounds);
}
@@ -1470,8 +1470,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
match impl_item.kind {
ty::AssocKind::Fn => {
- let ast_item = self.tcx.hir().expect_impl_item(def_id.expect_local());
- let hir::ImplItemKind::Fn(ref sig, body) = ast_item.kind else { bug!() };
+ let (sig, body) =
+ self.tcx.hir().expect_impl_item(def_id.expect_local()).expect_fn();
self.tables.asyncness.set_some(def_id.index, sig.header.asyncness);
record_array!(self.tables.fn_arg_names[def_id] <- self.tcx.hir().body_param_names(body));
// Can be inside `impl const Trait`, so using sig.header.constness is not reliable
@@ -1515,8 +1515,11 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
if encode_opt {
record!(self.tables.optimized_mir[def_id.to_def_id()] <- tcx.optimized_mir(def_id));
- if tcx.sess.opts.unstable_opts.drop_tracking_mir && let DefKind::Generator = self.tcx.def_kind(def_id) {
- record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- tcx.mir_generator_witnesses(def_id));
+ if tcx.sess.opts.unstable_opts.drop_tracking_mir
+ && let DefKind::Generator = self.tcx.def_kind(def_id)
+ && let Some(witnesses) = tcx.mir_generator_witnesses(def_id)
+ {
+ record!(self.tables.mir_generator_witnesses[def_id.to_def_id()] <- witnesses);
}
}
if encode_const {
@@ -1540,8 +1543,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id));
- let instance =
- ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id.to_def_id()));
+ let instance = ty::InstanceDef::Item(def_id.to_def_id());
let unused = tcx.unused_generic_params(instance);
self.tables.unused_generic_params.set(def_id.local_def_index, unused);
}
@@ -1619,7 +1621,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
debug!("EncodeContext::encode_info_for_item({:?})", def_id);
let record_associated_item_def_ids = |this: &mut Self, def_ids: &[DefId]| {
- record_array!(this.tables.children[def_id] <- def_ids.iter().map(|&def_id| {
+ record_array!(this.tables.associated_item_or_field_def_ids[def_id] <- def_ids.iter().map(|&def_id| {
assert!(def_id.is_local());
def_id.index
}))
@@ -1642,9 +1644,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
}
hir::ItemKind::OpaqueTy(ref opaque) => {
self.encode_explicit_item_bounds(def_id);
- self.tables
- .is_type_alias_impl_trait
- .set(def_id.index, matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias));
+ self.tables.is_type_alias_impl_trait.set(
+ def_id.index,
+ matches!(opaque.origin, hir::OpaqueTyOrigin::TyAlias { .. }),
+ );
}
hir::ItemKind::Impl(hir::Impl { defaultness, constness, .. }) => {
self.tables.impl_defaultness.set_some(def_id.index, *defaultness);
@@ -1680,6 +1683,10 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
hir::ItemKind::Trait(..) => {
record!(self.tables.trait_def[def_id] <- self.tcx.trait_def(def_id));
+ let module_children = tcx.module_children_local(item.owner_id.def_id);
+ record_array!(self.tables.module_children_non_reexports[def_id] <-
+ module_children.iter().map(|child| child.res.def_id().index));
+
let associated_item_def_ids = self.tcx.associated_item_def_ids(def_id);
record_associated_item_def_ids(self, associated_item_def_ids);
for &item_def_id in associated_item_def_ids {
@@ -1847,7 +1854,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_debugger_visualizers(&mut self) -> LazyArray<DebuggerVisualizerFile> {
empty_proc_macro!(self);
- self.lazy_array(self.tcx.debugger_visualizers(LOCAL_CRATE).iter())
+ self.lazy_array(
+ self.tcx
+ .debugger_visualizers(LOCAL_CRATE)
+ .iter()
+ // Erase the path since it may contain privacy sensitive data
+ // that we don't want to end up in crate metadata.
+ // The path is only needed for the local crate because of
+ // `--emit dep-info`.
+ .map(DebuggerVisualizerFile::path_erased),
+ )
}
fn encode_crate_deps(&mut self) -> LazyArray<CrateDep> {
@@ -1922,7 +1938,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> {
fn encode_traits(&mut self) -> LazyArray<DefIndex> {
empty_proc_macro!(self);
- self.lazy_array(self.tcx.traits_in_crate(LOCAL_CRATE).iter().map(|def_id| def_id.index))
+ self.lazy_array(self.tcx.traits(LOCAL_CRATE).iter().map(|def_id| def_id.index))
}
/// Encodes an index, mapping each trait to its (local) implementations.
@@ -2126,7 +2142,7 @@ fn prefetch_mir(tcx: TyCtxt<'_>) {
return;
}
- par_iter(tcx.mir_keys(())).for_each(|&def_id| {
+ par_for_each_in(tcx.mir_keys(()), |&def_id| {
let (encode_const, encode_opt) = should_encode_mir(tcx, def_id);
if encode_const {
@@ -2268,7 +2284,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) {
};
// Encode the rustc version string in a predictable location.
- rustc_version().encode(&mut ecx);
+ rustc_version(tcx.sess.cfg_version).encode(&mut ecx);
// Encode all the entries and extra information in the crate,
// culminating in the `CrateRoot` which points to all of it.
@@ -2313,7 +2329,7 @@ pub fn provide(providers: &mut Providers) {
.get(&def_id)
.expect("no traits in scope for a doc link")
},
- traits_in_crate: |tcx, LocalCrate| {
+ traits: |tcx, LocalCrate| {
let mut traits = Vec::new();
for id in tcx.hir().items() {
if matches!(tcx.def_kind(id.owner_id), DefKind::Trait | DefKind::TraitAlias) {
diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs
index 67710054c..97e67fcf8 100644
--- a/compiler/rustc_metadata/src/rmeta/mod.rs
+++ b/compiler/rustc_metadata/src/rmeta/mod.rs
@@ -2,26 +2,26 @@ use crate::creader::CrateMetadataRef;
use decoder::Metadata;
use def_path_hash_map::DefPathHashMapRef;
use rustc_data_structures::fx::FxHashMap;
+use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile;
use table::TableBuilder;
use rustc_ast as ast;
use rustc_attr as attr;
use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::MetadataRef;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, DocLinkResMap};
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, DefPathHash, StableCrateId};
use rustc_hir::definitions::DefKey;
use rustc_hir::lang_items::LangItem;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
use rustc_middle::mir;
+use rustc_middle::query::Providers;
use rustc_middle::ty::fast_reject::SimplifiedType;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, ReprOptions, Ty, UnusedGenericParams};
use rustc_middle::ty::{DeducedParamAttrs, GeneratorDiagnosticData, ParameterizedOverTcx, TyCtxt};
use rustc_serialize::opaque::FileEncoder;
@@ -49,8 +49,8 @@ mod def_path_hash_map;
mod encoder;
mod table;
-pub(crate) fn rustc_version() -> String {
- format!("rustc {}", option_env!("CFG_VERSION").unwrap_or("unknown version"))
+pub(crate) fn rustc_version(cfg_version: &'static str) -> String {
+ format!("rustc {}", cfg_version)
}
/// Metadata encoding version.
@@ -246,7 +246,7 @@ pub(crate) struct CrateRoot {
proc_macro_data: Option<ProcMacroData>,
tables: LazyTables,
- debugger_visualizers: LazyArray<rustc_span::DebuggerVisualizerFile>,
+ debugger_visualizers: LazyArray<DebuggerVisualizerFile>,
exported_symbols: LazyArray<(ExportedSymbol<'static>, SymbolExportInfo)>,
@@ -358,11 +358,18 @@ define_tables! {
associated_types_for_impl_traits_in_associated_fn: Table<DefIndex, LazyArray<DefId>>,
opt_rpitit_info: Table<DefIndex, Option<LazyValue<ty::ImplTraitInTraitData>>>,
unused_generic_params: Table<DefIndex, UnusedGenericParams>,
+ // Reexported names are not associated with individual `DefId`s,
+ // e.g. a glob import can introduce a lot of names, all with the same `DefId`.
+ // That's why the encoded list needs to contain `ModChild` structures describing all the names
+ // individually instead of `DefId`s.
module_children_reexports: Table<DefIndex, LazyArray<ModChild>>,
- optional:
attributes: Table<DefIndex, LazyArray<ast::Attribute>>,
- children: Table<DefIndex, LazyArray<DefIndex>>,
+ // For non-reexported names in a module every name is associated with a separate `DefId`,
+ // so we can take their names, visibilities etc from other encoded tables.
+ module_children_non_reexports: Table<DefIndex, LazyArray<DefIndex>>,
+ associated_item_or_field_def_ids: Table<DefIndex, LazyArray<DefIndex>>,
opt_def_kind: Table<DefIndex, DefKind>,
visibility: Table<DefIndex, LazyValue<ty::Visibility<DefIndex>>>,
def_span: Table<DefIndex, LazyValue<Span>>,
@@ -388,7 +395,7 @@ define_tables! {
mir_for_ctfe: Table<DefIndex, LazyValue<mir::Body<'static>>>,
mir_generator_witnesses: Table<DefIndex, LazyValue<mir::GeneratorLayout<'static>>>,
promoted_mir: Table<DefIndex, LazyValue<IndexVec<mir::Promoted, mir::Body<'static>>>>,
- thir_abstract_const: Table<DefIndex, LazyValue<ty::Const<'static>>>,
+ thir_abstract_const: Table<DefIndex, LazyValue<ty::EarlyBinder<ty::Const<'static>>>>,
impl_parent: Table<DefIndex, RawDefId>,
impl_polarity: Table<DefIndex, ty::ImplPolarity>,
constness: Table<DefIndex, hir::Constness>,
@@ -417,7 +424,7 @@ define_tables! {
macro_definition: Table<DefIndex, LazyValue<ast::DelimArgs>>,
proc_macro: Table<DefIndex, MacroKind>,
deduced_param_attrs: Table<DefIndex, LazyArray<DeducedParamAttrs>>,
- trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, Ty<'static>>>>,
+ trait_impl_trait_tys: Table<DefIndex, LazyValue<FxHashMap<DefId, ty::EarlyBinder<Ty<'static>>>>>,
doc_link_resolutions: Table<DefIndex, LazyValue<DocLinkResMap>>,
doc_link_traits_in_scope: Table<DefIndex, LazyArray<DefId>>,
}
diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs
index 364fa74ab..dda30bce2 100644
--- a/compiler/rustc_metadata/src/rmeta/table.rs
+++ b/compiler/rustc_metadata/src/rmeta/table.rs
@@ -2,7 +2,7 @@ use crate::rmeta::*;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_hir::def::{CtorKind, CtorOf};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::{ParameterizedOverTcx, UnusedGenericParams};
use rustc_serialize::opaque::FileEncoder;
use rustc_serialize::Encoder as _;
@@ -413,8 +413,8 @@ impl<I: Idx, const N: usize, T: FixedSizeEncoding<ByteArray = [u8; N]>> TableBui
// > Space requirements could perhaps be optimized by using the HAMT `popcnt`
// > trick (i.e. divide things into buckets of 32 or 64 items and then
// > store bit-masks of which item in each bucket is actually serialized).
- self.blocks.ensure_contains_elem(i, || [0; N]);
- value.write_to_bytes(&mut self.blocks[i]);
+ let block = self.blocks.ensure_contains_elem(i, || [0; N]);
+ value.write_to_bytes(block);
}
}
diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml
index 5b2ec9029..7c56af1da 100644
--- a/compiler/rustc_middle/Cargo.toml
+++ b/compiler/rustc_middle/Cargo.toml
@@ -11,6 +11,8 @@ chalk-ir = "0.87.0"
derive_more = "0.99.17"
either = "1.5.0"
gsgdt = "0.1.2"
+field-offset = "0.3.5"
+measureme = "10.0.0"
polonius-engine = "0.13.0"
rustc_apfloat = { path = "../rustc_apfloat" }
rustc_arena = { path = "../rustc_arena" }
@@ -21,6 +23,7 @@ rustc_errors = { path = "../rustc_errors" }
# Used for intra-doc links
rustc_error_messages = { path = "../rustc_error_messages" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_middle/messages.ftl b/compiler/rustc_middle/messages.ftl
index bd9d89dee..3d581daa9 100644
--- a/compiler/rustc_middle/messages.ftl
+++ b/compiler/rustc_middle/messages.ftl
@@ -1,40 +1,45 @@
+middle_cannot_be_normalized =
+ unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
+
+middle_conflict_types =
+ this expression supplies two conflicting concrete types for the same opaque type
+
+middle_const_eval_non_int =
+ constant evaluation of enum discriminant resulted in non-integer
+
+middle_const_not_used_in_type_alias =
+ const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
+
+middle_cycle =
+ a cycle occurred during layout computation
+
middle_drop_check_overflow =
overflow while adding drop-check rules for {$ty}
.note = overflowed on {$overflow_ty}
+middle_limit_invalid =
+ `limit` must be a non-negative integer
+ .label = {$error_str}
+
middle_opaque_hidden_type_mismatch =
concrete type differs from previous defining opaque type use
.label = expected `{$self_ty}`, got `{$other_ty}`
-middle_conflict_types =
- this expression supplies two conflicting concrete types for the same opaque type
-
middle_previous_use_here =
previous use here
-middle_limit_invalid =
- `limit` must be a non-negative integer
- .label = {$error_str}
-
middle_recursion_limit_reached =
reached the recursion limit finding the struct tail for `{$ty}`
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]`
-middle_const_eval_non_int =
- constant evaluation of enum discriminant resulted in non-integer
+middle_requires_lang_item = requires `{$name}` lang_item
+
+middle_strict_coherence_needs_negative_coherence =
+ to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
+ .label = due to this attribute
middle_unknown_layout =
the type `{$ty}` has an unknown layout
middle_values_too_big =
values of the type `{$ty}` are too big for the current architecture
-
-middle_cannot_be_normalized =
- unable to determine layout for `{$ty}` because `{$failure_ty}` cannot be normalized
-
-middle_strict_coherence_needs_negative_coherence =
- to use `strict_coherence` on this trait, the `with_negative_coherence` feature must be enabled
- .label = due to this attribute
-
-middle_const_not_used_in_type_alias =
- const parameter `{$ct}` is part of concrete type but not used in parameter list for the `impl Trait` type alias
diff --git a/compiler/rustc_middle/src/arena.rs b/compiler/rustc_middle/src/arena.rs
index dd1e254f4..a149a61ec 100644
--- a/compiler/rustc_middle/src/arena.rs
+++ b/compiler/rustc_middle/src/arena.rs
@@ -17,13 +17,13 @@ macro_rules! arena_types {
[decode] mir: rustc_middle::mir::Body<'tcx>,
[] steal_promoted:
rustc_data_structures::steal::Steal<
- rustc_index::vec::IndexVec<
+ rustc_index::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<'tcx>
>
>,
[decode] promoted:
- rustc_index::vec::IndexVec<
+ rustc_index::IndexVec<
rustc_middle::mir::Promoted,
rustc_middle::mir::Body<'tcx>
>,
@@ -114,9 +114,14 @@ macro_rules! arena_types {
[] dep_kind: rustc_middle::dep_graph::DepKindStruct<'tcx>,
- [decode] trait_impl_trait_tys: rustc_data_structures::fx::FxHashMap<rustc_hir::def_id::DefId, rustc_middle::ty::Ty<'tcx>>,
+ [decode] trait_impl_trait_tys:
+ rustc_data_structures::fx::FxHashMap<
+ rustc_hir::def_id::DefId,
+ rustc_middle::ty::EarlyBinder<rustc_middle::ty::Ty<'tcx>>
+ >,
[] bit_set_u32: rustc_index::bit_set::BitSet<u32>,
[] external_constraints: rustc_middle::traits::solve::ExternalConstraintsData<'tcx>,
+ [] predefined_opaques_in_body: rustc_middle::traits::solve::PredefinedOpaquesData<'tcx>,
[decode] doc_link_resolutions: rustc_hir::def::DocLinkResMap,
[] closure_kind_origin: (rustc_span::Span, rustc_middle::hir::place::Place<'tcx>),
[] mod_child: rustc_middle::metadata::ModChild,
diff --git a/compiler/rustc_middle/src/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs
index 865bb70af..2dc5b8969 100644
--- a/compiler/rustc_middle/src/dep_graph/dep_node.rs
+++ b/compiler/rustc_middle/src/dep_graph/dep_node.rs
@@ -357,20 +357,20 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
Fingerprint::new(
// `owner` is local, so is completely defined by the local hash
def_path_hash.local_hash(),
- local_id.as_u32().into(),
+ local_id.as_u32() as u64,
)
}
#[inline(always)]
fn to_debug_str(&self, tcx: TyCtxt<'tcx>) -> String {
let HirId { owner, local_id } = *self;
- format!("{}.{}", tcx.def_path_str(owner.to_def_id()), local_id.as_u32())
+ format!("{}.{}", tcx.def_path_str(owner), local_id.as_u32())
}
#[inline(always)]
fn recover(tcx: TyCtxt<'tcx>, dep_node: &DepNode) -> Option<Self> {
if tcx.fingerprint_style(dep_node.kind) == FingerprintStyle::HirId {
- let (local_hash, local_id) = Fingerprint::from(dep_node.hash).as_value();
+ let (local_hash, local_id) = Fingerprint::from(dep_node.hash).split();
let def_path_hash = DefPathHash::new(tcx.sess.local_stable_crate_id(), local_hash);
let def_id = tcx
.def_path_hash_to_def_id(def_path_hash, &mut || {
@@ -378,6 +378,7 @@ impl<'tcx> DepNodeParams<TyCtxt<'tcx>> for HirId {
})
.expect_local();
let local_id = local_id
+ .as_u64()
.try_into()
.unwrap_or_else(|_| panic!("local id should be u32, found {:?}", local_id));
Some(HirId { owner: OwnerId { def_id }, local_id: ItemLocalId::from_u32(local_id) })
diff --git a/compiler/rustc_middle/src/error.rs b/compiler/rustc_middle/src/error.rs
index dc4aa1864..046186d27 100644
--- a/compiler/rustc_middle/src/error.rs
+++ b/compiler/rustc_middle/src/error.rs
@@ -1,5 +1,5 @@
use rustc_macros::Diagnostic;
-use rustc_span::Span;
+use rustc_span::{Span, Symbol};
use crate::ty::Ty;
@@ -74,6 +74,14 @@ pub(crate) struct StrictCoherenceNeedsNegativeCoherence {
}
#[derive(Diagnostic)]
+#[diag(middle_requires_lang_item)]
+pub(crate) struct RequiresLangItem {
+ #[primary_span]
+ pub span: Option<Span>,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
#[diag(middle_const_not_used_in_type_alias)]
pub(super) struct ConstNotUsedTraitAlias {
pub ct: String,
diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs
index e551c76f8..d1ddc8fc1 100644
--- a/compiler/rustc_middle/src/hir/map/mod.rs
+++ b/compiler/rustc_middle/src/hir/map/mod.rs
@@ -1,17 +1,18 @@
use crate::hir::{ModuleItems, Owner};
+use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
use crate::query::LocalCrate;
use crate::ty::TyCtxt;
use rustc_ast as ast;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync};
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathData, DefPathHash};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::*;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::hir::nested_filter;
use rustc_span::def_id::StableCrateId;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
@@ -150,11 +151,6 @@ impl<'hir> Map<'hir> {
self.tcx.hir_module_items(module).items()
}
- #[inline]
- pub fn par_for_each_item(self, f: impl Fn(ItemId) + Sync + Send) {
- par_for_each_in(&self.tcx.hir_crate_items(()).items[..], |id| f(*id));
- }
-
pub fn def_key(self, def_id: LocalDefId) -> DefKey {
// Accessing the DefKey is ok, since it is part of DefPathHash.
self.tcx.definitions_untracked().def_key(def_id)
@@ -414,7 +410,7 @@ impl<'hir> Map<'hir> {
/// item (possibly associated), a closure, or a `hir::AnonConst`.
pub fn body_owner(self, BodyId { hir_id }: BodyId) -> HirId {
let parent = self.parent_id(hir_id);
- assert!(self.find(parent).map_or(false, |n| is_body_owner(n, hir_id)), "{hir_id:?}");
+ assert!(self.find(parent).is_some_and(|n| is_body_owner(n, hir_id)), "{hir_id:?}");
parent
}
@@ -502,7 +498,7 @@ impl<'hir> Map<'hir> {
}
#[inline]
- pub fn par_body_owners(self, f: impl Fn(LocalDefId) + Sync + Send) {
+ pub fn par_body_owners(self, f: impl Fn(LocalDefId) + DynSend + DynSync) {
par_for_each_in(&self.tcx.hir_crate_items(()).body_owners[..], |&def_id| f(def_id));
}
@@ -640,7 +636,7 @@ impl<'hir> Map<'hir> {
}
#[inline]
- pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + Sync + Send) {
+ pub fn par_for_each_module(self, f: impl Fn(LocalDefId) + DynSend + DynSync) {
let crate_items = self.tcx.hir_crate_items(());
par_for_each_in(&crate_items.submodules[..], |module| f(module.def_id))
}
@@ -1170,11 +1166,26 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
source_file_names.sort_unstable();
+ // We have to take care of debugger visualizers explicitly. The HIR (and
+ // thus `hir_body_hash`) contains the #[debugger_visualizer] attributes but
+ // these attributes only store the file path to the visualizer file, not
+ // their content. Yet that content is exported into crate metadata, so any
+ // changes to it need to be reflected in the crate hash.
+ let debugger_visualizers: Vec<_> = tcx
+ .debugger_visualizers(LOCAL_CRATE)
+ .iter()
+ // We ignore the path to the visualizer file since it's not going to be
+ // encoded in crate metadata and we already hash the full contents of
+ // the file.
+ .map(DebuggerVisualizerFile::path_erased)
+ .collect();
+
let crate_hash: Fingerprint = tcx.with_stable_hashing_context(|mut hcx| {
let mut stable_hasher = StableHasher::new();
hir_body_hash.hash_stable(&mut hcx, &mut stable_hasher);
upstream_crates.hash_stable(&mut hcx, &mut stable_hasher);
source_file_names.hash_stable(&mut hcx, &mut stable_hasher);
+ debugger_visualizers.hash_stable(&mut hcx, &mut stable_hasher);
if tcx.sess.opts.incremental_relative_spans() {
let definitions = tcx.definitions_untracked();
let mut owner_spans: Vec<_> = krate
@@ -1199,7 +1210,7 @@ pub(super) fn crate_hash(tcx: TyCtxt<'_>, _: LocalCrate) -> Svh {
stable_hasher.finish()
});
- Svh::new(crate_hash.to_smaller_hash())
+ Svh::new(crate_hash)
}
fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
@@ -1217,7 +1228,7 @@ fn upstream_crates(tcx: TyCtxt<'_>) -> Vec<(StableCrateId, Svh)> {
}
fn hir_id_to_string(map: Map<'_>, id: HirId) -> String {
- let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id.to_def_id());
+ let path_str = |def_id: LocalDefId| map.tcx.def_path_str(def_id);
let span_str = || map.tcx.sess.source_map().span_to_snippet(map.span(id)).unwrap_or_default();
let node_str = |prefix| format!("{id} ({prefix} `{}`)", span_str());
diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs
index 7770a5e47..45a07fdd2 100644
--- a/compiler/rustc_middle/src/hir/mod.rs
+++ b/compiler/rustc_middle/src/hir/mod.rs
@@ -6,10 +6,11 @@ pub mod map;
pub mod nested_filter;
pub mod place;
-use crate::ty::query::Providers;
+use crate::query::Providers;
use crate::ty::{EarlyBinder, ImplSubject, TyCtxt};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
+use rustc_data_structures::sync::{par_for_each_in, DynSend, DynSync};
+use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::*;
use rustc_query_system::ich::StableHashingContext;
@@ -77,19 +78,19 @@ impl ModuleItems {
self.owners().map(|id| id.def_id)
}
- pub fn par_items(&self, f: impl Fn(ItemId) + Send + Sync) {
+ pub fn par_items(&self, f: impl Fn(ItemId) + DynSend + DynSync) {
par_for_each_in(&self.items[..], |&id| f(id))
}
- pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + Send + Sync) {
+ pub fn par_trait_items(&self, f: impl Fn(TraitItemId) + DynSend + DynSync) {
par_for_each_in(&self.trait_items[..], |&id| f(id))
}
- pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + Send + Sync) {
+ pub fn par_impl_items(&self, f: impl Fn(ImplItemId) + DynSend + DynSync) {
par_for_each_in(&self.impl_items[..], |&id| f(id))
}
- pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + Send + Sync) {
+ pub fn par_foreign_items(&self, f: impl Fn(ForeignItemId) + DynSend + DynSync) {
par_for_each_in(&self.foreign_items[..], |&id| f(id))
}
}
@@ -110,6 +111,12 @@ impl<'tcx> TyCtxt<'tcx> {
None => self.type_of(def_id).map_bound(ImplSubject::Inherent),
}
}
+
+ /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
+ pub fn is_foreign_item(self, def_id: impl Into<DefId>) -> bool {
+ self.opt_parent(def_id.into())
+ .is_some_and(|parent| matches!(self.def_kind(parent), DefKind::ForeignMod))
+ }
}
pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_middle/src/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs
index 80b4c964c..8a22de931 100644
--- a/compiler/rustc_middle/src/hir/place.rs
+++ b/compiler/rustc_middle/src/hir/place.rs
@@ -66,7 +66,6 @@ pub struct Place<'tcx> {
///
/// This is an HIR version of [`rustc_middle::mir::Place`].
#[derive(Clone, Debug, PartialEq, Eq, Hash, TyEncodable, TyDecodable, HashStable)]
-#[derive(TypeFoldable, TypeVisitable)]
pub struct PlaceWithHirId<'tcx> {
/// `HirId` of the expression or pattern producing this value.
pub hir_id: HirId,
diff --git a/compiler/rustc_middle/src/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs
index b5b712c36..561713149 100644
--- a/compiler/rustc_middle/src/infer/canonical.rs
+++ b/compiler/rustc_middle/src/infer/canonical.rs
@@ -280,7 +280,7 @@ pub struct QueryResponse<'tcx, R> {
/// should get its hidden type inferred. So we bubble the opaque type
/// and the type it was compared against upwards and let the query caller
/// handle it.
- pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
+ pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
pub value: R,
}
@@ -348,14 +348,6 @@ impl<'tcx, R> Canonical<'tcx, QueryResponse<'tcx, R>> {
}
}
-impl<'tcx, R> Canonical<'tcx, ty::ParamEnvAnd<'tcx, R>> {
- #[inline]
- pub fn without_const(mut self) -> Self {
- self.value = self.value.without_const();
- self
- }
-}
-
impl<'tcx, V> Canonical<'tcx, V> {
/// Allows you to map the `value` of a canonical while keeping the
/// same set of bound variables.
@@ -400,10 +392,8 @@ pub type QueryOutlivesConstraint<'tcx> =
(ty::OutlivesPredicate<GenericArg<'tcx>, Region<'tcx>>, ConstraintCategory<'tcx>);
TrivialTypeTraversalAndLiftImpls! {
- for <'tcx> {
- crate::infer::canonical::Certainty,
- crate::infer::canonical::CanonicalTyVarKind,
- }
+ crate::infer::canonical::Certainty,
+ crate::infer::canonical::CanonicalTyVarKind,
}
impl<'tcx> CanonicalVarValues<'tcx> {
diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs
index b4edb02f6..22ee2a8c5 100644
--- a/compiler/rustc_middle/src/lib.rs
+++ b/compiler/rustc_middle/src/lib.rs
@@ -59,6 +59,8 @@
#![feature(result_option_inspect)]
#![feature(const_option)]
#![feature(trait_alias)]
+#![feature(ptr_alignment_type)]
+#![feature(macro_metavar_expr)]
#![recursion_limit = "512"]
#![allow(rustc::potential_query_instability)]
@@ -74,7 +76,7 @@ extern crate tracing;
extern crate smallvec;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
#[cfg(test)]
mod tests;
@@ -83,12 +85,7 @@ mod tests;
mod macros;
#[macro_use]
-pub mod query;
-
-#[macro_use]
pub mod arena;
-#[macro_use]
-pub mod dep_graph;
pub(crate) mod error;
pub mod hir;
pub mod infer;
@@ -99,12 +96,13 @@ pub mod mir;
pub mod thir;
pub mod traits;
pub mod ty;
+pub mod util;
mod values;
-pub mod util {
- pub mod bug;
- pub mod common;
-}
+#[macro_use]
+pub mod query;
+#[macro_use]
+pub mod dep_graph;
// Allows macros to refer to this crate as `::rustc_middle`
extern crate self as rustc_middle;
diff --git a/compiler/rustc_middle/src/lint.rs b/compiler/rustc_middle/src/lint.rs
index c61de97d5..14343ac11 100644
--- a/compiler/rustc_middle/src/lint.rs
+++ b/compiler/rustc_middle/src/lint.rs
@@ -231,19 +231,19 @@ pub fn explain_lint_level_source(
let name = lint.name_lower();
match src {
LintLevelSource::Default => {
- err.note_once(&format!("`#[{}({})]` on by default", level.as_str(), name));
+ err.note_once(format!("`#[{}({})]` on by default", level.as_str(), name));
}
LintLevelSource::CommandLine(lint_flag_val, orig_level) => {
let flag = orig_level.to_cmd_flag();
let hyphen_case_lint_name = name.replace('_', "-");
if lint_flag_val.as_str() == name {
- err.note_once(&format!(
+ err.note_once(format!(
"requested on the command line with `{} {}`",
flag, hyphen_case_lint_name
));
} else {
let hyphen_case_flag_val = lint_flag_val.as_str().replace('_', "-");
- err.note_once(&format!(
+ err.note_once(format!(
"`{} {}` implied by `{} {}`",
flag, hyphen_case_lint_name, flag, hyphen_case_flag_val
));
@@ -256,7 +256,7 @@ pub fn explain_lint_level_source(
err.span_note_once(span, "the lint level is defined here");
if lint_attr_name.as_str() != name {
let level_str = level.as_str();
- err.note_once(&format!(
+ err.note_once(format!(
"`#[{}({})]` implied by `#[{}({})]`",
level_str, name, level_str, lint_attr_name
));
@@ -444,12 +444,12 @@ pub fn struct_lint_level(
};
if future_incompatible.explain_reason {
- err.warn(&explanation);
+ err.warn(explanation);
}
if !future_incompatible.reference.is_empty() {
let citation =
format!("for more information, see {}", future_incompatible.reference);
- err.note(&citation);
+ err.note(citation);
}
}
@@ -468,8 +468,7 @@ pub fn struct_lint_level(
pub fn in_external_macro(sess: &Session, span: Span) -> bool {
let expn_data = span.ctxt().outer_expn_data();
match expn_data.kind {
- ExpnKind::Inlined
- | ExpnKind::Root
+ ExpnKind::Root
| ExpnKind::Desugaring(
DesugaringKind::ForLoop | DesugaringKind::WhileLoop | DesugaringKind::OpaqueTy,
) => false,
diff --git a/compiler/rustc_middle/src/macros.rs b/compiler/rustc_middle/src/macros.rs
index 89014f62d..cd1c6c330 100644
--- a/compiler/rustc_middle/src/macros.rs
+++ b/compiler/rustc_middle/src/macros.rs
@@ -43,34 +43,26 @@ macro_rules! span_bug {
#[macro_export]
macro_rules! CloneLiftImpls {
- (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+ ($($ty:ty,)+) => {
$(
- impl<$tcx> $crate::ty::Lift<$tcx> for $ty {
+ impl<'tcx> $crate::ty::Lift<'tcx> for $ty {
type Lifted = Self;
- fn lift_to_tcx(self, _: $crate::ty::TyCtxt<$tcx>) -> Option<Self> {
+ fn lift_to_tcx(self, _: $crate::ty::TyCtxt<'tcx>) -> Option<Self> {
Some(self)
}
}
)+
};
-
- ($($ty:ty,)+) => {
- CloneLiftImpls! {
- for <'tcx> {
- $($ty,)+
- }
- }
- };
}
/// Used for types that are `Copy` and which **do not care arena
/// allocated data** (i.e., don't need to be folded).
#[macro_export]
macro_rules! TrivialTypeTraversalImpls {
- (for <$tcx:lifetime> { $($ty:ty,)+ }) => {
+ ($($ty:ty,)+) => {
$(
- impl<$tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<$tcx>> for $ty {
- fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<$tcx>>>(
+ impl<'tcx> $crate::ty::fold::TypeFoldable<$crate::ty::TyCtxt<'tcx>> for $ty {
+ fn try_fold_with<F: $crate::ty::fold::FallibleTypeFolder<$crate::ty::TyCtxt<'tcx>>>(
self,
_: &mut F,
) -> ::std::result::Result<Self, F::Error> {
@@ -78,7 +70,7 @@ macro_rules! TrivialTypeTraversalImpls {
}
#[inline]
- fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<$tcx>>>(
+ fn fold_with<F: $crate::ty::fold::TypeFolder<$crate::ty::TyCtxt<'tcx>>>(
self,
_: &mut F,
) -> Self {
@@ -86,9 +78,9 @@ macro_rules! TrivialTypeTraversalImpls {
}
}
- impl<$tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<$tcx>> for $ty {
+ impl<'tcx> $crate::ty::visit::TypeVisitable<$crate::ty::TyCtxt<'tcx>> for $ty {
#[inline]
- fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<$tcx>>>(
+ fn visit_with<F: $crate::ty::visit::TypeVisitor<$crate::ty::TyCtxt<'tcx>>>(
&self,
_: &mut F)
-> ::std::ops::ControlFlow<F::BreakTy>
@@ -98,14 +90,6 @@ macro_rules! TrivialTypeTraversalImpls {
}
)+
};
-
- ($($ty:ty,)+) => {
- TrivialTypeTraversalImpls! {
- for<'tcx> {
- $($ty,)+
- }
- }
- };
}
#[macro_export]
diff --git a/compiler/rustc_middle/src/metadata.rs b/compiler/rustc_middle/src/metadata.rs
index f3170e0ec..674402cb4 100644
--- a/compiler/rustc_middle/src/metadata.rs
+++ b/compiler/rustc_middle/src/metadata.rs
@@ -4,7 +4,6 @@ use rustc_hir::def::Res;
use rustc_macros::HashStable;
use rustc_span::def_id::DefId;
use rustc_span::symbol::Ident;
-use rustc_span::Span;
use smallvec::SmallVec;
/// A simplified version of `ImportKind` from resolve.
@@ -41,8 +40,6 @@ pub struct ModChild {
pub res: Res<!>,
/// Visibility of the item.
pub vis: ty::Visibility<DefId>,
- /// Span of the item.
- pub span: Span,
/// Reexport chain linking this module child to its original reexported item.
/// Empty if the module child is a proper item.
pub reexport_chain: SmallVec<[Reexport; 2]>,
diff --git a/compiler/rustc_middle/src/middle/debugger_visualizer.rs b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
new file mode 100644
index 000000000..a0497d805
--- /dev/null
+++ b/compiler/rustc_middle/src/middle/debugger_visualizer.rs
@@ -0,0 +1,38 @@
+use rustc_data_structures::sync::Lrc;
+use std::path::PathBuf;
+
+#[derive(HashStable)]
+#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
+pub enum DebuggerVisualizerType {
+ Natvis,
+ GdbPrettyPrinter,
+}
+
+/// A single debugger visualizer file.
+#[derive(HashStable)]
+#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
+pub struct DebuggerVisualizerFile {
+ /// The complete debugger visualizer source.
+ pub src: Lrc<[u8]>,
+ /// Indicates which visualizer type this targets.
+ pub visualizer_type: DebuggerVisualizerType,
+ /// The file path to the visualizer file. This is used for reporting
+ /// visualizer files in dep-info. Before it is written to crate metadata,
+ /// the path is erased to `None`, so as not to emit potentially privacy
+ /// sensitive data.
+ pub path: Option<PathBuf>,
+}
+
+impl DebuggerVisualizerFile {
+ pub fn new(src: Lrc<[u8]>, visualizer_type: DebuggerVisualizerType, path: PathBuf) -> Self {
+ DebuggerVisualizerFile { src, visualizer_type, path: Some(path) }
+ }
+
+ pub fn path_erased(&self) -> Self {
+ DebuggerVisualizerFile {
+ src: self.src.clone(),
+ visualizer_type: self.visualizer_type,
+ path: None,
+ }
+ }
+}
diff --git a/compiler/rustc_middle/src/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs
index c0c0fd07b..9041da9a0 100644
--- a/compiler/rustc_middle/src/middle/exported_symbols.rs
+++ b/compiler/rustc_middle/src/middle/exported_symbols.rs
@@ -72,6 +72,6 @@ pub fn metadata_symbol_name(tcx: TyCtxt<'_>) -> String {
format!(
"rust_metadata_{}_{:08x}",
tcx.crate_name(LOCAL_CRATE),
- tcx.sess.local_stable_crate_id().to_u64(),
+ tcx.sess.local_stable_crate_id(),
)
}
diff --git a/compiler/rustc_middle/src/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs
index 343ea1f00..9a633e04c 100644
--- a/compiler/rustc_middle/src/middle/lang_items.rs
+++ b/compiler/rustc_middle/src/middle/lang_items.rs
@@ -18,12 +18,8 @@ impl<'tcx> TyCtxt<'tcx> {
/// Returns the `DefId` for a given `LangItem`.
/// If not found, fatally aborts compilation.
pub fn require_lang_item(self, lang_item: LangItem, span: Option<Span>) -> DefId {
- self.lang_items().require(lang_item).unwrap_or_else(|err| {
- if let Some(span) = span {
- self.sess.span_fatal(span, err.to_string())
- } else {
- self.sess.fatal(err.to_string())
- }
+ self.lang_items().get(lang_item).unwrap_or_else(|| {
+ self.sess.emit_fatal(crate::error::RequiresLangItem { span, name: lang_item.name() });
})
}
diff --git a/compiler/rustc_middle/src/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs
index 12aef66bc..bd859d4d6 100644
--- a/compiler/rustc_middle/src/middle/limits.rs
+++ b/compiler/rustc_middle/src/middle/limits.rs
@@ -11,7 +11,7 @@
use crate::bug;
use crate::error::LimitInvalid;
-use crate::ty;
+use crate::query::Providers;
use rustc_ast::Attribute;
use rustc_session::Session;
use rustc_session::{Limit, Limits};
@@ -19,7 +19,7 @@ use rustc_span::symbol::{sym, Symbol};
use std::num::IntErrorKind;
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
providers.limits = |tcx, ()| Limits {
recursion_limit: get_recursion_limit(tcx.hir().krate_attrs(), tcx.sess),
move_size_limit: get_limit(
diff --git a/compiler/rustc_middle/src/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs
index 9c25f3009..85c5af9ca 100644
--- a/compiler/rustc_middle/src/middle/mod.rs
+++ b/compiler/rustc_middle/src/middle/mod.rs
@@ -1,4 +1,5 @@
pub mod codegen_fn_attrs;
+pub mod debugger_visualizer;
pub mod dependency_format;
pub mod exported_symbols;
pub mod lang_items;
@@ -32,6 +33,6 @@ pub mod region;
pub mod resolve_bound_vars;
pub mod stability;
-pub fn provide(providers: &mut crate::ty::query::Providers) {
+pub fn provide(providers: &mut crate::query::Providers) {
limits::provide(providers);
}
diff --git a/compiler/rustc_middle/src/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs
index 967fed687..f45cf788d 100644
--- a/compiler/rustc_middle/src/middle/privacy.rs
+++ b/compiler/rustc_middle/src/middle/privacy.rs
@@ -64,7 +64,7 @@ impl EffectiveVisibility {
self.at_level(level).is_public()
}
- pub fn from_vis(vis: Visibility) -> EffectiveVisibility {
+ pub const fn from_vis(vis: Visibility) -> EffectiveVisibility {
EffectiveVisibility {
direct: vis,
reexported: vis,
@@ -72,6 +72,18 @@ impl EffectiveVisibility {
reachable_through_impl_trait: vis,
}
}
+
+ #[must_use]
+ pub fn min(mut self, lhs: EffectiveVisibility, tcx: TyCtxt<'_>) -> Self {
+ for l in Level::all_levels() {
+ let rhs_vis = self.at_level_mut(l);
+ let lhs_vis = *lhs.at_level(l);
+ if rhs_vis.is_at_least(lhs_vis, tcx) {
+ *rhs_vis = lhs_vis;
+ };
+ }
+ self
+ }
}
/// Holds a map of effective visibilities for reachable HIR nodes.
@@ -82,8 +94,7 @@ pub struct EffectiveVisibilities<Id = LocalDefId> {
impl EffectiveVisibilities {
pub fn is_public_at_level(&self, id: LocalDefId, level: Level) -> bool {
- self.effective_vis(id)
- .map_or(false, |effective_vis| effective_vis.is_public_at_level(level))
+ self.effective_vis(id).is_some_and(|effective_vis| effective_vis.is_public_at_level(level))
}
/// See `Level::Reachable`.
@@ -137,24 +148,6 @@ impl EffectiveVisibilities {
};
}
- pub fn set_public_at_level(
- &mut self,
- id: LocalDefId,
- lazy_private_vis: impl FnOnce() -> Visibility,
- level: Level,
- ) {
- let mut effective_vis = self
- .effective_vis(id)
- .copied()
- .unwrap_or_else(|| EffectiveVisibility::from_vis(lazy_private_vis()));
- for l in Level::all_levels() {
- if l <= level {
- *effective_vis.at_level_mut(l) = Visibility::Public;
- }
- }
- self.map.insert(id, effective_vis);
- }
-
pub fn check_invariants(&self, tcx: TyCtxt<'_>, early: bool) {
if !cfg!(debug_assertions) {
return;
@@ -219,7 +212,7 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
pub fn update(
&mut self,
id: Id,
- nominal_vis: Visibility,
+ nominal_vis: Option<Visibility>,
lazy_private_vis: impl FnOnce() -> Visibility,
inherited_effective_vis: EffectiveVisibility,
level: Level,
@@ -243,12 +236,11 @@ impl<Id: Eq + Hash> EffectiveVisibilities<Id> {
if !(inherited_effective_vis_at_prev_level == inherited_effective_vis_at_level
&& level != l)
{
- calculated_effective_vis =
- if nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
- inherited_effective_vis_at_level
- } else {
- nominal_vis
- };
+ calculated_effective_vis = if let Some(nominal_vis) = nominal_vis && !nominal_vis.is_at_least(inherited_effective_vis_at_level, tcx) {
+ nominal_vis
+ } else {
+ inherited_effective_vis_at_level
+ }
}
// effective visibility can't be decreased at next update call for the
// same id
diff --git a/compiler/rustc_middle/src/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs
index 94ca38c0e..10712e146 100644
--- a/compiler/rustc_middle/src/middle/region.rs
+++ b/compiler/rustc_middle/src/middle/region.rs
@@ -203,7 +203,7 @@ impl Scope {
pub type ScopeDepth = u32;
/// The region scope tree encodes information about region relationships.
-#[derive(TyEncodable, TyDecodable, Default, Debug)]
+#[derive(Default, Debug)]
pub struct ScopeTree {
/// If not empty, this body is the root of this region hierarchy.
pub root_body: Option<hir::HirId>,
@@ -317,13 +317,13 @@ pub struct ScopeTree {
/// candidates in general). In constants, the `lifetime` field is None
/// to indicate that certain expressions escape into 'static and
/// should have no local cleanup scope.
-#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+#[derive(Debug, Copy, Clone, HashStable)]
pub enum RvalueCandidateType {
Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
}
-#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
+#[derive(Debug, Copy, Clone, HashStable)]
pub struct YieldData {
/// The `Span` of the yield.
pub span: Span,
diff --git a/compiler/rustc_middle/src/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs
index b61f7806b..6354c0aab 100644
--- a/compiler/rustc_middle/src/middle/stability.rs
+++ b/compiler/rustc_middle/src/middle/stability.rs
@@ -115,8 +115,8 @@ pub fn report_unstable(
soft_handler(SOFT_UNSTABLE, span, &msg)
} else {
let mut err =
- feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), &msg);
- if let Some((inner_types, ref msg, sugg, applicability)) = suggestion {
+ feature_err_issue(&sess.parse_sess, feature, span, GateIssue::Library(issue), msg);
+ if let Some((inner_types, msg, sugg, applicability)) = suggestion {
err.span_suggestion(inner_types, msg, sugg, applicability);
}
err.emit();
@@ -170,7 +170,7 @@ pub fn deprecation_suggestion(
if let Some(suggestion) = suggestion {
diag.span_suggestion_verbose(
span,
- &format!("replace the use of the deprecated {}", kind),
+ format!("replace the use of the deprecated {}", kind),
suggestion,
Applicability::MachineApplicable,
);
@@ -375,7 +375,7 @@ impl<'tcx> TyCtxt<'tcx> {
let parent_def_id = self.hir().get_parent_item(id);
let skip = self
.lookup_deprecation_entry(parent_def_id.to_def_id())
- .map_or(false, |parent_depr| parent_depr.same_origin(&depr_entry));
+ .is_some_and(|parent_depr| parent_depr.same_origin(&depr_entry));
// #[deprecated] doesn't emit a notice if we're not on the
// topmost deprecation. For example, if a struct is deprecated,
@@ -599,7 +599,7 @@ impl<'tcx> TyCtxt<'tcx> {
|span, def_id| {
// The API could be uncallable for other reasons, for example when a private module
// was referenced.
- self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id));
+ self.sess.delay_span_bug(span, format!("encountered unmarked API: {:?}", def_id));
},
)
}
diff --git a/compiler/rustc_middle/src/mir/basic_blocks.rs b/compiler/rustc_middle/src/mir/basic_blocks.rs
index 3fb468379..9d70dbfa0 100644
--- a/compiler/rustc_middle/src/mir/basic_blocks.rs
+++ b/compiler/rustc_middle/src/mir/basic_blocks.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::graph;
use rustc_data_structures::graph::dominators::{dominators, Dominators};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::sync::OnceCell;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use smallvec::SmallVec;
@@ -27,6 +27,7 @@ struct Cache {
switch_sources: OnceCell<SwitchSources>,
is_cyclic: OnceCell<bool>,
postorder: OnceCell<Vec<BasicBlock>>,
+ dominators: OnceCell<Dominators<BasicBlock>>,
}
impl<'tcx> BasicBlocks<'tcx> {
@@ -41,8 +42,8 @@ impl<'tcx> BasicBlocks<'tcx> {
*self.cache.is_cyclic.get_or_init(|| graph::is_cyclic(self))
}
- pub fn dominators(&self) -> Dominators<BasicBlock> {
- dominators(&self)
+ pub fn dominators(&self) -> &Dominators<BasicBlock> {
+ self.cache.dominators.get_or_init(|| dominators(self))
}
/// Returns predecessors for each basic block.
diff --git a/compiler/rustc_middle/src/mir/graphviz.rs b/compiler/rustc_middle/src/mir/graphviz.rs
index cf6d46e1e..2de73db3a 100644
--- a/compiler/rustc_middle/src/mir/graphviz.rs
+++ b/compiler/rustc_middle/src/mir/graphviz.rs
@@ -16,19 +16,16 @@ where
{
let def_ids = dump_mir_def_ids(tcx, single);
- let mirs =
- def_ids
- .iter()
- .flat_map(|def_id| {
- if tcx.is_const_fn_raw(*def_id) {
- vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
- } else {
- vec![tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
- *def_id,
- )))]
- }
- })
- .collect::<Vec<_>>();
+ let mirs = def_ids
+ .iter()
+ .flat_map(|def_id| {
+ if tcx.is_const_fn_raw(*def_id) {
+ vec![tcx.optimized_mir(*def_id), tcx.mir_for_ctfe(*def_id)]
+ } else {
+ vec![tcx.instance_mir(ty::InstanceDef::Item(*def_id))]
+ }
+ })
+ .collect::<Vec<_>>();
let use_subgraphs = mirs.len() > 1;
if use_subgraphs {
diff --git a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
index dcb56a175..d4dd56a42 100644
--- a/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
+++ b/compiler/rustc_middle/src/mir/interpret/allocation/init_mask.rs
@@ -5,7 +5,9 @@ use std::hash;
use std::iter;
use std::ops::Range;
+use rustc_serialize::{Decodable, Encodable};
use rustc_target::abi::Size;
+use rustc_type_ir::{TyDecoder, TyEncoder};
use super::AllocRange;
@@ -182,11 +184,39 @@ impl InitMask {
/// The actual materialized blocks of the bitmask, when we can't keep the `InitMask` lazy.
// Note: for performance reasons when interning, some of the fields can be partially
// hashed. (see the `Hash` impl below for more details), so the impl is not derived.
-#[derive(Clone, Debug, Eq, PartialEq, TyEncodable, TyDecodable, HashStable)]
+#[derive(Clone, Debug, Eq, PartialEq, HashStable)]
struct InitMaskMaterialized {
blocks: Vec<Block>,
}
+// `Block` is a `u64`, but it is a bitmask not a numeric value. If we were to just derive
+// Encodable and Decodable we would apply varint encoding to the bitmasks, which is slower
+// and also produces more output when the high bits of each `u64` are occupied.
+// Note: There is probably a remaining optimization for masks that do not use an entire
+// `Block`.
+impl<E: TyEncoder> Encodable<E> for InitMaskMaterialized {
+ fn encode(&self, encoder: &mut E) {
+ encoder.emit_usize(self.blocks.len());
+ for block in &self.blocks {
+ encoder.emit_raw_bytes(&block.to_le_bytes());
+ }
+ }
+}
+
+// This implementation is deliberately not derived, see the matching `Encodable` impl.
+impl<D: TyDecoder> Decodable<D> for InitMaskMaterialized {
+ fn decode(decoder: &mut D) -> Self {
+ let num_blocks = decoder.read_usize();
+ let mut blocks = Vec::with_capacity(num_blocks);
+ for _ in 0..num_blocks {
+ let bytes = decoder.read_raw_bytes(8);
+ let block = u64::from_le_bytes(bytes.try_into().unwrap());
+ blocks.push(block);
+ }
+ InitMaskMaterialized { blocks }
+ }
+}
+
// Const allocations are only hashed for interning. However, they can be large, making the hashing
// expensive especially since it uses `FxHash`: it's better suited to short keys, not potentially
// big buffers like the allocation's init mask. We can partially hash some fields when they're
diff --git a/compiler/rustc_middle/src/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs
index c5137cf06..055d8e9a3 100644
--- a/compiler/rustc_middle/src/mir/interpret/error.rs
+++ b/compiler/rustc_middle/src/mir/interpret/error.rs
@@ -1,7 +1,8 @@
use super::{AllocId, AllocRange, ConstAlloc, Pointer, Scalar};
use crate::mir::interpret::ConstValue;
-use crate::ty::{layout, query::TyCtxtAt, tls, Ty, ValTree};
+use crate::query::TyCtxtAt;
+use crate::ty::{layout, tls, Ty, ValTree};
use rustc_data_structures::sync::Lock;
use rustc_errors::{pluralize, struct_span_err, DiagnosticBuilder, ErrorGuaranteed};
@@ -15,15 +16,49 @@ use std::{any::Any, backtrace::Backtrace, fmt};
pub enum ErrorHandled {
/// Already reported an error for this evaluation, and the compilation is
/// *guaranteed* to fail. Warnings/lints *must not* produce `Reported`.
- Reported(ErrorGuaranteed),
+ Reported(ReportedErrorInfo),
/// Don't emit an error, the evaluation failed because the MIR was generic
/// and the substs didn't fully monomorphize it.
TooGeneric,
}
impl From<ErrorGuaranteed> for ErrorHandled {
- fn from(err: ErrorGuaranteed) -> ErrorHandled {
- ErrorHandled::Reported(err)
+ #[inline]
+ fn from(error: ErrorGuaranteed) -> ErrorHandled {
+ ErrorHandled::Reported(error.into())
+ }
+}
+
+#[derive(Debug, Copy, Clone, PartialEq, Eq, HashStable, TyEncodable, TyDecodable)]
+pub struct ReportedErrorInfo {
+ error: ErrorGuaranteed,
+ is_tainted_by_errors: bool,
+}
+
+impl ReportedErrorInfo {
+ #[inline]
+ pub fn tainted_by_errors(error: ErrorGuaranteed) -> ReportedErrorInfo {
+ ReportedErrorInfo { is_tainted_by_errors: true, error }
+ }
+
+ /// Returns true if evaluation failed because MIR was tainted by errors.
+ #[inline]
+ pub fn is_tainted_by_errors(self) -> bool {
+ self.is_tainted_by_errors
+ }
+}
+
+impl From<ErrorGuaranteed> for ReportedErrorInfo {
+ #[inline]
+ fn from(error: ErrorGuaranteed) -> ReportedErrorInfo {
+ ReportedErrorInfo { is_tainted_by_errors: false, error }
+ }
+}
+
+impl Into<ErrorGuaranteed> for ReportedErrorInfo {
+ #[inline]
+ fn into(self) -> ErrorGuaranteed {
+ self.error
}
}
@@ -89,7 +124,7 @@ fn print_backtrace(backtrace: &Backtrace) {
impl From<ErrorGuaranteed> for InterpErrorInfo<'_> {
fn from(err: ErrorGuaranteed) -> Self {
- InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err)).into()
+ InterpError::InvalidProgram(InvalidProgramInfo::AlreadyReported(err.into())).into()
}
}
@@ -125,7 +160,7 @@ pub enum InvalidProgramInfo<'tcx> {
/// Resolution can fail if we are in a too generic context.
TooGeneric,
/// Abort in case errors are already reported.
- AlreadyReported(ErrorGuaranteed),
+ AlreadyReported(ReportedErrorInfo),
/// An error occurred during layout computation.
Layout(layout::LayoutError<'tcx>),
/// An error occurred during FnAbi computation: the passed --target lacks FFI support
@@ -134,6 +169,9 @@ pub enum InvalidProgramInfo<'tcx> {
FnAbiAdjustForForeignAbi(call::AdjustForForeignAbiError),
/// SizeOf of unsized type was requested.
SizeOfUnsizedType(Ty<'tcx>),
+ /// An unsized local was accessed without having been initialized.
+ /// This is not meaningful as we can't even have backing memory for such locals.
+ UninitUnsizedLocal,
}
impl fmt::Display for InvalidProgramInfo<'_> {
@@ -141,7 +179,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
use InvalidProgramInfo::*;
match self {
TooGeneric => write!(f, "encountered overly generic constant"),
- AlreadyReported(ErrorGuaranteed { .. }) => {
+ AlreadyReported(_) => {
write!(
f,
"an error has already been reported elsewhere (this should not usually be printed)"
@@ -150,6 +188,7 @@ impl fmt::Display for InvalidProgramInfo<'_> {
Layout(ref err) => write!(f, "{err}"),
FnAbiAdjustForForeignAbi(ref err) => write!(f, "{err}"),
SizeOfUnsizedType(ty) => write!(f, "size_of called on unsized type `{ty}`"),
+ UninitUnsizedLocal => write!(f, "unsized local is used while uninitialized"),
}
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs
index 1f8b650e3..3620385fa 100644
--- a/compiler/rustc_middle/src/mir/interpret/mod.rs
+++ b/compiler/rustc_middle/src/mir/interpret/mod.rs
@@ -120,8 +120,8 @@ use crate::ty::{self, Instance, Ty, TyCtxt};
pub use self::error::{
struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult,
EvalToValTreeResult, InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo,
- MachineStopType, ResourceExhaustionInfo, ScalarSizeMismatch, UndefinedBehaviorInfo,
- UninitBytesAccess, UnsupportedOpInfo,
+ MachineStopType, ReportedErrorInfo, ResourceExhaustionInfo, ScalarSizeMismatch,
+ UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo,
};
pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar};
@@ -227,7 +227,9 @@ pub fn specialized_encode_alloc_id<'tcx, E: TyEncoder<I = TyCtxt<'tcx>>>(
// References to statics doesn't need to know about their allocations,
// just about its `DefId`.
AllocDiscriminant::Static.encode(encoder);
- did.encode(encoder);
+ // Cannot use `did.encode(encoder)` because of a bug around
+ // specializations and method calls.
+ Encodable::<E>::encode(&did, encoder);
}
}
}
diff --git a/compiler/rustc_middle/src/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs
index 60927eed8..65d049193 100644
--- a/compiler/rustc_middle/src/mir/interpret/pointer.rs
+++ b/compiler/rustc_middle/src/mir/interpret/pointer.rs
@@ -102,7 +102,7 @@ impl<T: HasDataLayout> PointerArithmetic for T {}
/// This trait abstracts over the kind of provenance that is associated with a `Pointer`. It is
/// mostly opaque; the `Machine` trait extends it with some more operations that also have access to
/// some global state.
-/// The `Debug` rendering is used to distplay bare provenance, and for the default impl of `fmt`.
+/// The `Debug` rendering is used to display bare provenance, and for the default impl of `fmt`.
pub trait Provenance: Copy + fmt::Debug {
/// Says whether the `offset` field of `Pointer`s with this provenance is the actual physical address.
/// - If `false`, the offset *must* be relative. This means the bytes representing a pointer are
diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs
index 856d821a5..f53dc8cb0 100644
--- a/compiler/rustc_middle/src/mir/interpret/queries.rs
+++ b/compiler/rustc_middle/src/mir/interpret/queries.rs
@@ -1,9 +1,10 @@
use super::{ErrorHandled, EvalToConstValueResult, EvalToValTreeResult, GlobalId};
use crate::mir;
+use crate::query::{TyCtxtAt, TyCtxtEnsure};
use crate::ty::subst::InternalSubsts;
use crate::ty::visit::TypeVisitableExt;
-use crate::ty::{self, query::TyCtxtAt, query::TyCtxtEnsure, TyCtxt};
+use crate::ty::{self, TyCtxt};
use rustc_hir::def::DefKind;
use rustc_hir::def_id::DefId;
use rustc_session::lint;
@@ -42,7 +43,7 @@ impl<'tcx> TyCtxt<'tcx> {
span: Option<Span>,
) -> EvalToConstValueResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
- // variables. We reject those here since `resolve_opt_const_arg`
+ // variables. We reject those here since `resolve`
// would fail otherwise.
//
// When trying to evaluate constants containing inference variables,
@@ -51,7 +52,7 @@ impl<'tcx> TyCtxt<'tcx> {
bug!("did not expect inference variables here");
}
- match ty::Instance::resolve_opt_const_arg(
+ match ty::Instance::resolve(
self, param_env,
// FIXME: maybe have a separate version for resolving mir::UnevaluatedConst?
ct.def, ct.substs,
@@ -61,7 +62,7 @@ impl<'tcx> TyCtxt<'tcx> {
self.const_eval_global_id(param_env, cid, span)
}
Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
+ Err(err) => Err(ErrorHandled::Reported(err.into())),
}
}
@@ -73,7 +74,7 @@ impl<'tcx> TyCtxt<'tcx> {
span: Option<Span>,
) -> EvalToValTreeResult<'tcx> {
// Cannot resolve `Unevaluated` constants that contain inference
- // variables. We reject those here since `resolve_opt_const_arg`
+ // variables. We reject those here since `resolve`
// would fail otherwise.
//
// When trying to evaluate constants containing inference variables,
@@ -82,7 +83,7 @@ impl<'tcx> TyCtxt<'tcx> {
bug!("did not expect inference variables here");
}
- match ty::Instance::resolve_opt_const_arg(self, param_env, ct.def, ct.substs) {
+ match ty::Instance::resolve(self, param_env, ct.def, ct.substs) {
Ok(Some(instance)) => {
let cid = GlobalId { instance, promoted: None };
self.const_eval_global_id_for_typeck(param_env, cid, span).inspect(|_| {
@@ -94,14 +95,14 @@ impl<'tcx> TyCtxt<'tcx> {
// used generic parameters is a bug of evaluation, so checking for it
// here does feel somewhat sensible.
if !self.features().generic_const_exprs && ct.substs.has_non_region_param() {
- assert!(matches!(self.def_kind(ct.def.did), DefKind::AnonConst));
- let mir_body = self.mir_for_ctfe_opt_const_arg(ct.def);
+ assert!(matches!(self.def_kind(ct.def), DefKind::AnonConst));
+ let mir_body = self.mir_for_ctfe(ct.def);
if mir_body.is_polymorphic {
- let Some(local_def_id) = ct.def.did.as_local() else { return };
+ let Some(local_def_id) = ct.def.as_local() else { return };
self.struct_span_lint_hir(
lint::builtin::CONST_EVALUATABLE_UNCHECKED,
self.hir().local_def_id_to_hir_id(local_def_id),
- self.def_span(ct.def.did),
+ self.def_span(ct.def),
"cannot use constants which depend on generic parameters in types",
|err| err,
)
@@ -110,7 +111,7 @@ impl<'tcx> TyCtxt<'tcx> {
})
}
Ok(None) => Err(ErrorHandled::TooGeneric),
- Err(error_reported) => Err(ErrorHandled::Reported(error_reported)),
+ Err(err) => Err(ErrorHandled::Reported(err.into())),
}
}
diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs
index 2ea8602af..5c71910a9 100644
--- a/compiler/rustc_middle/src/mir/mod.rs
+++ b/compiler/rustc_middle/src/mir/mod.rs
@@ -9,7 +9,7 @@ use crate::mir::visit::MirVisitable;
use crate::ty::codec::{TyDecoder, TyEncoder};
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable};
use crate::ty::print::{FmtPrinter, Printer};
-use crate::ty::visit::{TypeVisitable, TypeVisitableExt, TypeVisitor};
+use crate::ty::visit::TypeVisitableExt;
use crate::ty::{self, List, Ty, TyCtxt};
use crate::ty::{AdtDef, InstanceDef, ScalarInt, UserTypeAnnotationIndex};
use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
@@ -27,7 +27,7 @@ use polonius_engine::Atom;
pub use rustc_ast::Mutability;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::graph::dominators::Dominators;
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_serialize::{Decodable, Encodable};
use rustc_span::symbol::Symbol;
use rustc_span::{Span, DUMMY_SP};
@@ -36,7 +36,7 @@ use either::Either;
use std::borrow::Cow;
use std::fmt::{self, Debug, Display, Formatter, Write};
-use std::ops::{ControlFlow, Index, IndexMut};
+use std::ops::{Index, IndexMut};
use std::{iter, mem};
pub use self::query::*;
@@ -101,7 +101,7 @@ impl<'tcx> HasLocalDecls<'tcx> for Body<'tcx> {
/// pass will be named after the type, and it will consist of a main
/// loop that goes over each available MIR and applies `run_pass`.
pub trait MirPass<'tcx> {
- fn name(&self) -> &str {
+ fn name(&self) -> &'static str {
let name = std::any::type_name::<Self>();
if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
}
@@ -191,20 +191,13 @@ pub struct MirSource<'tcx> {
impl<'tcx> MirSource<'tcx> {
pub fn item(def_id: DefId) -> Self {
- MirSource {
- instance: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
- promoted: None,
- }
+ MirSource { instance: InstanceDef::Item(def_id), promoted: None }
}
pub fn from_instance(instance: InstanceDef<'tcx>) -> Self {
MirSource { instance, promoted: None }
}
- pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
- self.instance.with_opt_param()
- }
-
#[inline]
pub fn def_id(&self) -> DefId {
self.instance.def_id()
@@ -714,9 +707,7 @@ pub enum BindingForm<'tcx> {
}
TrivialTypeTraversalAndLiftImpls! {
- for<'tcx> {
- BindingForm<'tcx>,
- }
+ BindingForm<'tcx>,
}
mod binding_form_impl {
@@ -1120,6 +1111,10 @@ pub struct VarDebugInfo<'tcx> {
/// originated from (starting from 1). Note, if MIR inlining is enabled, then this is the
/// argument number in the original function before it was inlined.
pub argument_index: Option<u16>,
+
+ /// The data represents `name` dereferenced `references` times,
+ /// and not the direct value.
+ pub references: u8,
}
///////////////////////////////////////////////////////////////////////////
@@ -1533,6 +1528,19 @@ impl<V, T> ProjectionElem<V, T> {
}
}
+ /// Returns `true` if the target of this projection always refers to the same memory region
+ /// whatever the state of the program.
+ pub fn is_stable_offset(&self) -> bool {
+ match self {
+ Self::Deref | Self::Index(_) => false,
+ Self::Field(_, _)
+ | Self::OpaqueCast(_)
+ | Self::ConstantIndex { .. }
+ | Self::Subslice { .. }
+ | Self::Downcast(_, _) => true,
+ }
+ }
+
/// Returns `true` if this is a `Downcast` projection with the given `VariantIdx`.
pub fn is_downcast_to(&self, v: VariantIdx) -> bool {
matches!(*self, Self::Downcast(_, x) if x == v)
@@ -1546,8 +1554,11 @@ impl<V, T> ProjectionElem<V, T> {
/// Returns `true` if this is accepted inside `VarDebugInfoContents::Place`.
pub fn can_use_in_debuginfo(&self) -> bool {
match self {
- Self::Deref | Self::Downcast(_, _) | Self::Field(_, _) => true,
- Self::ConstantIndex { .. }
+ Self::ConstantIndex { from_end: false, .. }
+ | Self::Deref
+ | Self::Downcast(_, _)
+ | Self::Field(_, _) => true,
+ Self::ConstantIndex { from_end: true, .. }
| Self::Index(_)
| Self::OpaqueCast(_)
| Self::Subslice { .. } => false,
@@ -1635,18 +1646,7 @@ impl<'tcx> Place<'tcx> {
return self;
}
- let mut v: Vec<PlaceElem<'tcx>>;
-
- let new_projections = if self.projection.is_empty() {
- more_projections
- } else {
- v = Vec::with_capacity(self.projection.len() + more_projections.len());
- v.extend(self.projection);
- v.extend(more_projections);
- &v
- };
-
- Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
+ self.as_ref().project_deeper(more_projections, tcx)
}
}
@@ -1717,6 +1717,27 @@ impl<'tcx> PlaceRef<'tcx> {
(base, *proj)
})
}
+
+ /// Generates a new place by appending `more_projections` to the existing ones
+ /// and interning the result.
+ pub fn project_deeper(
+ self,
+ more_projections: &[PlaceElem<'tcx>],
+ tcx: TyCtxt<'tcx>,
+ ) -> Place<'tcx> {
+ let mut v: Vec<PlaceElem<'tcx>>;
+
+ let new_projections = if self.projection.is_empty() {
+ more_projections
+ } else {
+ v = Vec::with_capacity(self.projection.len() + more_projections.len());
+ v.extend(self.projection);
+ v.extend(more_projections);
+ &v
+ };
+
+ Place { local: self.local, projection: tcx.mk_place_elems(new_projections) }
+ }
}
impl Debug for Place<'_> {
@@ -2050,7 +2071,11 @@ impl<'tcx> Debug for Rvalue<'tcx> {
}
UnaryOp(ref op, ref a) => write!(fmt, "{:?}({:?})", op, a),
Discriminant(ref place) => write!(fmt, "discriminant({:?})", place),
- NullaryOp(ref op, ref t) => write!(fmt, "{:?}({:?})", op, t),
+ NullaryOp(ref op, ref t) => match op {
+ NullOp::SizeOf => write!(fmt, "SizeOf({:?})", t),
+ NullOp::AlignOf => write!(fmt, "AlignOf({:?})", t),
+ NullOp::OffsetOf(fields) => write!(fmt, "OffsetOf({:?}, {:?})", t, fields),
+ },
ThreadLocalRef(did) => ty::tls::with(|tcx| {
let muta = tcx.static_mutability(did).unwrap().prefix_str();
write!(fmt, "&/*tls*/ {}{}", muta, tcx.def_path_str(did))
@@ -2305,7 +2330,7 @@ impl<'tcx> ConstantKind<'tcx> {
if let Some(val) = c.kind().try_eval_for_mir(tcx, param_env) {
match val {
Ok(val) => Self::Val(val, c.ty()),
- Err(_) => Self::Ty(tcx.const_error(self.ty())),
+ Err(guar) => Self::Ty(tcx.const_error(self.ty(), guar)),
}
} else {
self
@@ -2317,9 +2342,7 @@ impl<'tcx> ConstantKind<'tcx> {
match tcx.const_eval_resolve(param_env, uneval, None) {
Ok(val) => Self::Val(val, ty),
Err(ErrorHandled::TooGeneric) => self,
- Err(ErrorHandled::Reported(guar)) => {
- Self::Ty(tcx.const_error_with_guaranteed(ty, guar))
- }
+ Err(ErrorHandled::Reported(guar)) => Self::Ty(tcx.const_error(ty, guar.into())),
}
}
}
@@ -2438,16 +2461,6 @@ impl<'tcx> ConstantKind<'tcx> {
Self::Val(val, ty)
}
- /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
- /// converted to a constant, everything else becomes `Unevaluated`.
- pub fn from_anon_const(
- tcx: TyCtxt<'tcx>,
- def_id: LocalDefId,
- param_env: ty::ParamEnv<'tcx>,
- ) -> Self {
- Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id), param_env)
- }
-
#[instrument(skip(tcx), level = "debug", ret)]
pub fn from_inline_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
let hir_id = tcx.hir().local_def_id_to_hir_id(def_id);
@@ -2487,28 +2500,25 @@ impl<'tcx> ConstantKind<'tcx> {
ty::InlineConstSubsts::new(tcx, ty::InlineConstSubstsParts { parent_substs, ty })
.substs;
- let uneval = UnevaluatedConst {
- def: ty::WithOptConstParam::unknown(def_id).to_global(),
- substs,
- promoted: None,
- };
+ let uneval = UnevaluatedConst { def: def_id.to_def_id(), substs, promoted: None };
debug_assert!(!uneval.has_free_regions());
Self::Unevaluated(uneval, ty)
}
+ /// Literals are converted to `ConstantKindVal`, const generic parameters are eagerly
+ /// converted to a constant, everything else becomes `Unevaluated`.
#[instrument(skip(tcx), level = "debug", ret)]
- fn from_opt_const_arg_anon_const(
+ pub fn from_anon_const(
tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
param_env: ty::ParamEnv<'tcx>,
) -> Self {
- let body_id = match tcx.hir().get_by_def_id(def.did) {
+ let body_id = match tcx.hir().get_by_def_id(def) {
hir::Node::AnonConst(ac) => ac.body,
- _ => span_bug!(
- tcx.def_span(def.did.to_def_id()),
- "from_anon_const can only process anonymous constants"
- ),
+ _ => {
+ span_bug!(tcx.def_span(def), "from_anon_const can only process anonymous constants")
+ }
};
let expr = &tcx.hir().body(body_id).value;
@@ -2524,7 +2534,7 @@ impl<'tcx> ConstantKind<'tcx> {
};
debug!("expr.kind: {:?}", expr.kind);
- let ty = tcx.type_of(def.def_id_for_type_of()).subst_identity();
+ let ty = tcx.type_of(def).subst_identity();
debug!(?ty);
// FIXME(const_generics): We currently have to special case parameters because `min_const_generics`
@@ -2551,7 +2561,7 @@ impl<'tcx> ConstantKind<'tcx> {
_ => {}
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
let parent_substs = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id)
&& let Some(parent_did) = parent_hir_id.as_owner()
{
@@ -2561,15 +2571,14 @@ impl<'tcx> ConstantKind<'tcx> {
};
debug!(?parent_substs);
- let did = def.did.to_def_id();
+ let did = def.to_def_id();
let child_substs = InternalSubsts::identity_for_item(tcx, did);
let substs =
tcx.mk_substs_from_iter(parent_substs.into_iter().chain(child_substs.into_iter()));
debug!(?substs);
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
- let span = tcx.hir().span(hir_id);
- let uneval = UnevaluatedConst::new(def.to_global(), substs);
+ let span = tcx.def_span(def);
+ let uneval = UnevaluatedConst::new(did, substs);
debug!(?span, ?param_env);
match tcx.const_eval_resolve(param_env, uneval, Some(span)) {
@@ -2583,8 +2592,8 @@ impl<'tcx> ConstantKind<'tcx> {
// new unevaluated const and error hard later in codegen
Self::Unevaluated(
UnevaluatedConst {
- def: def.to_global(),
- substs: InternalSubsts::identity_for_item(tcx, def.did),
+ def: did,
+ substs: InternalSubsts::identity_for_item(tcx, did),
promoted: None,
},
ty,
@@ -2609,7 +2618,7 @@ impl<'tcx> ConstantKind<'tcx> {
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
- pub def: ty::WithOptConstParam<DefId>,
+ pub def: DefId,
pub substs: SubstsRef<'tcx>,
pub promoted: Option<Promoted>,
}
@@ -2625,10 +2634,7 @@ impl<'tcx> UnevaluatedConst<'tcx> {
impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
- pub fn new(
- def: ty::WithOptConstParam<DefId>,
- substs: SubstsRef<'tcx>,
- ) -> UnevaluatedConst<'tcx> {
+ pub fn new(def: DefId, substs: SubstsRef<'tcx>) -> UnevaluatedConst<'tcx> {
UnevaluatedConst { def, substs, promoted: Default::default() }
}
}
@@ -2744,13 +2750,12 @@ impl<'tcx> UserTypeProjections {
/// `field[0]` (aka `.0`), indicating that the type of `s` is
/// determined by finding the type of the `.0` field from `T`.
#[derive(Clone, Debug, TyEncodable, TyDecodable, Hash, HashStable, PartialEq)]
+#[derive(TypeFoldable, TypeVisitable)]
pub struct UserTypeProjection {
pub base: UserTypeAnnotationIndex,
pub projs: Vec<ProjectionKind>,
}
-impl Copy for ProjectionKind {}
-
impl UserTypeProjection {
pub(crate) fn index(mut self) -> Self {
self.projs.push(ProjectionElem::Index(()));
@@ -2787,28 +2792,6 @@ impl UserTypeProjection {
}
}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for UserTypeProjection {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(UserTypeProjection {
- base: self.base.try_fold_with(folder)?,
- projs: self.projs.try_fold_with(folder)?,
- })
- }
-}
-
-impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for UserTypeProjection {
- fn visit_with<Vs: TypeVisitor<TyCtxt<'tcx>>>(
- &self,
- visitor: &mut Vs,
- ) -> ControlFlow<Vs::BreakTy> {
- self.base.visit_with(visitor)
- // Note: there's nothing in `self.proj` to visit.
- }
-}
-
rustc_index::newtype_index! {
#[derive(HashStable)]
#[debug_format = "promoted[{}]"]
@@ -3116,11 +3099,13 @@ mod size_asserts {
use super::*;
use rustc_data_structures::static_assert_size;
// tidy-alphabetical-start
- static_assert_size!(BasicBlockData<'_>, 144);
+ static_assert_size!(BasicBlockData<'_>, 136);
static_assert_size!(LocalDecl<'_>, 40);
+ static_assert_size!(SourceScopeData<'_>, 72);
static_assert_size!(Statement<'_>, 32);
static_assert_size!(StatementKind<'_>, 16);
- static_assert_size!(Terminator<'_>, 112);
- static_assert_size!(TerminatorKind<'_>, 96);
+ static_assert_size!(Terminator<'_>, 104);
+ static_assert_size!(TerminatorKind<'_>, 88);
+ static_assert_size!(VarDebugInfo<'_>, 80);
// tidy-alphabetical-end
}
diff --git a/compiler/rustc_middle/src/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs
index f592f1515..f31b343c9 100644
--- a/compiler/rustc_middle/src/mir/mono.rs
+++ b/compiler/rustc_middle/src/mir/mono.rs
@@ -4,10 +4,10 @@ use rustc_attr::InlineAttr;
use rustc_data_structures::base_n;
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash128, HashStable, StableHasher};
use rustc_hir::def_id::{CrateNum, DefId, LOCAL_CRATE};
use rustc_hir::ItemId;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_query_system::ich::StableHashingContext;
use rustc_session::config::OptLevel;
use rustc_span::source_map::Span;
@@ -313,8 +313,8 @@ impl<'tcx> CodegenUnit<'tcx> {
// avoid collisions and is still reasonably short for filenames.
let mut hasher = StableHasher::new();
human_readable_name.hash(&mut hasher);
- let hash: u128 = hasher.finish();
- let hash = hash & ((1u128 << 80) - 1);
+ let hash: Hash128 = hasher.finish();
+ let hash = hash.as_u128() & ((1u128 << 80) - 1);
base_n::encode(hash, base_n::CASE_INSENSITIVE)
}
@@ -334,10 +334,7 @@ impl<'tcx> CodegenUnit<'tcx> {
}
pub fn modify_size_estimate(&mut self, delta: usize) {
- assert!(self.size_estimate.is_some());
- if let Some(size_estimate) = self.size_estimate {
- self.size_estimate = Some(size_estimate + delta);
- }
+ *self.size_estimate.as_mut().unwrap() += delta;
}
pub fn contains_item(&self, item: &MonoItem<'tcx>) -> bool {
@@ -373,7 +370,7 @@ impl<'tcx> CodegenUnit<'tcx> {
// instances into account. The others don't matter for
// the codegen tests and can even make item order
// unstable.
- InstanceDef::Item(def) => def.did.as_local().map(Idx::index),
+ InstanceDef::Item(def) => def.as_local().map(Idx::index),
InstanceDef::VTableShim(..)
| InstanceDef::ReifyShim(..)
| InstanceDef::Intrinsic(..)
@@ -505,22 +502,13 @@ impl<'tcx> CodegenUnitNameBuilder<'tcx> {
// instantiating stuff for upstream crates.
let local_crate_id = if cnum != LOCAL_CRATE {
let local_stable_crate_id = tcx.sess.local_stable_crate_id();
- format!(
- "-in-{}.{:08x}",
- tcx.crate_name(LOCAL_CRATE),
- local_stable_crate_id.to_u64() as u32,
- )
+ format!("-in-{}.{:08x}", tcx.crate_name(LOCAL_CRATE), local_stable_crate_id)
} else {
String::new()
};
let stable_crate_id = tcx.sess.local_stable_crate_id();
- format!(
- "{}.{:08x}{}",
- tcx.crate_name(cnum),
- stable_crate_id.to_u64() as u32,
- local_crate_id,
- )
+ format!("{}.{:08x}{}", tcx.crate_name(cnum), stable_crate_id, local_crate_id)
});
write!(cgu_name, "{}", crate_prefix).unwrap();
diff --git a/compiler/rustc_middle/src/mir/patch.rs b/compiler/rustc_middle/src/mir/patch.rs
index f62853c3e..c4c3341f8 100644
--- a/compiler/rustc_middle/src/mir/patch.rs
+++ b/compiler/rustc_middle/src/mir/patch.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::*;
use rustc_middle::ty::Ty;
use rustc_span::Span;
diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs
index 7e5195359..62c3d8cf2 100644
--- a/compiler/rustc_middle/src/mir/pretty.rs
+++ b/compiler/rustc_middle/src/mir/pretty.rs
@@ -10,7 +10,7 @@ use super::spanview::write_mir_fn_spanview;
use either::Either;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::interpret::{
alloc_range, read_target_uint, AllocBytes, AllocId, Allocation, ConstAllocation, ConstValue,
GlobalAlloc, Pointer, Provenance,
@@ -298,8 +298,7 @@ pub fn write_mir_pretty<'tcx>(
// are shared between mir_for_ctfe and optimized_mir
write_mir_fn(tcx, tcx.mir_for_ctfe(def_id), &mut |_, _| Ok(()), w)?;
} else {
- let instance_mir =
- tcx.instance_mir(ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)));
+ let instance_mir = tcx.instance_mir(ty::InstanceDef::Item(def_id));
render_body(w, instance_mir)?;
}
}
@@ -464,11 +463,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
ConstantKind::Ty(ct) => match ct.kind() {
ty::ConstKind::Param(p) => format!("Param({})", p),
ty::ConstKind::Unevaluated(uv) => {
- format!(
- "Unevaluated({}, {:?})",
- self.tcx.def_path_str(uv.def.did),
- uv.substs,
- )
+ format!("Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.substs,)
}
ty::ConstKind::Value(val) => format!("Value({})", fmt_valtree(&val)),
ty::ConstKind::Error(_) => "Error".to_string(),
@@ -481,7 +476,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> {
ConstantKind::Unevaluated(uv, _) => {
format!(
"Unevaluated({}, {:?}, {:?})",
- self.tcx.def_path_str(uv.def.did),
+ self.tcx.def_path_str(uv.def),
uv.substs,
uv.promoted,
)
@@ -556,8 +551,13 @@ fn write_scope_tree(
}
let indented_debug_info = format!(
- "{0:1$}debug {2} => {3:?};",
- INDENT, indent, var_debug_info.name, var_debug_info.value,
+ "{0:1$}debug {2} => {3:&<4$}{5:?};",
+ INDENT,
+ indent,
+ var_debug_info.name,
+ "",
+ var_debug_info.references as usize,
+ var_debug_info.value,
);
writeln!(
diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs
index cfdf1dcf5..53fd2dd23 100644
--- a/compiler/rustc_middle/src/mir/query.rs
+++ b/compiler/rustc_middle/src/mir/query.rs
@@ -1,14 +1,14 @@
//! Values computed by queries that use MIR.
-use crate::mir::{Body, ConstantKind, Promoted};
+use crate::mir::ConstantKind;
use crate::ty::{self, OpaqueHiddenType, Ty, TyCtxt};
use rustc_data_structures::fx::FxIndexMap;
use rustc_data_structures::unord::UnordSet;
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::BitMatrix;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_span::Span;
use rustc_target::abi::{FieldIdx, VariantIdx};
use smallvec::SmallVec;
@@ -454,42 +454,3 @@ pub struct CoverageInfo {
/// The total number of coverage region counter expressions added to the MIR `Body`.
pub num_expressions: u32,
}
-
-/// Shims which make dealing with `WithOptConstParam` easier.
-///
-/// For more information on why this is needed, consider looking
-/// at the docs for `WithOptConstParam` itself.
-impl<'tcx> TyCtxt<'tcx> {
- #[inline]
- pub fn mir_const_qualif_opt_const_arg(
- self,
- def: ty::WithOptConstParam<LocalDefId>,
- ) -> ConstQualifs {
- if let Some(param_did) = def.const_param_did {
- self.mir_const_qualif_const_arg((def.did, param_did))
- } else {
- self.mir_const_qualif(def.did)
- }
- }
-
- #[inline]
- pub fn promoted_mir_opt_const_arg(
- self,
- def: ty::WithOptConstParam<DefId>,
- ) -> &'tcx IndexVec<Promoted, Body<'tcx>> {
- if let Some((did, param_did)) = def.as_const_arg() {
- self.promoted_mir_of_const_arg((did, param_did))
- } else {
- self.promoted_mir(def.did)
- }
- }
-
- #[inline]
- pub fn mir_for_ctfe_opt_const_arg(self, def: ty::WithOptConstParam<DefId>) -> &'tcx Body<'tcx> {
- if let Some((did, param_did)) = def.as_const_arg() {
- self.mir_for_ctfe_of_const_arg((did, param_did))
- } else {
- self.mir_for_ctfe(def.did)
- }
- }
-}
diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs
index 93800d484..3e474c1d3 100644
--- a/compiler/rustc_middle/src/mir/syntax.rs
+++ b/compiler/rustc_middle/src/mir/syntax.rs
@@ -16,7 +16,7 @@ use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece};
use rustc_hir::def_id::DefId;
use rustc_hir::{self as hir};
use rustc_hir::{self, GeneratorKind};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_target::abi::{FieldIdx, VariantIdx};
use rustc_ast::Mutability;
@@ -256,7 +256,7 @@ pub enum StatementKind<'tcx> {
/// **Needs clarification**: The implication of the above idea would be that assignment implies
/// that the resulting value is initialized. I believe we could commit to this separately from
/// committing to whatever part of the memory model we would need to decide on to make the above
- /// paragragh precise. Do we want to?
+ /// paragraph precise. Do we want to?
///
/// Assignments in which the types of the place and rvalue differ are not well-formed.
///
@@ -336,9 +336,8 @@ pub enum StatementKind<'tcx> {
/// This is especially useful for `let _ = PLACE;` bindings that desugar to a single
/// `PlaceMention(PLACE)`.
///
- /// When executed at runtime this is a nop.
- ///
- /// Disallowed after drop elaboration.
+ /// When executed at runtime, this computes the given place, but then discards
+ /// it without doing a load. It is UB if the place is not pointing to live memory.
PlaceMention(Box<Place<'tcx>>),
/// Encodes a user's type ascription. These need to be preserved
@@ -609,7 +608,11 @@ pub enum TerminatorKind<'tcx> {
/// > The drop glue is executed if, among all statements executed within this `Body`, an assignment to
/// > the place or one of its "parents" occurred more recently than a move out of it. This does not
/// > consider indirect assignments.
- Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction },
+ ///
+ /// The `replace` flag indicates whether this terminator was created as part of an assignment.
+ /// This should only be used for diagnostic purposes, and does not have any operational
+ /// meaning.
+ Drop { place: Place<'tcx>, target: BasicBlock, unwind: UnwindAction, replace: bool },
/// Roughly speaking, evaluates the `func` operand and the arguments, and starts execution of
/// the referred to function. The operand types must match the argument types of the function.
@@ -657,7 +660,7 @@ pub enum TerminatorKind<'tcx> {
Assert {
cond: Operand<'tcx>,
expected: bool,
- msg: AssertMessage<'tcx>,
+ msg: Box<AssertMessage<'tcx>>,
target: BasicBlock,
unwind: UnwindAction,
},
@@ -755,6 +758,29 @@ pub enum TerminatorKind<'tcx> {
},
}
+impl TerminatorKind<'_> {
+ /// Returns a simple string representation of a `TerminatorKind` variant, independent of any
+ /// values it might hold (e.g. `TerminatorKind::Call` always returns `"Call"`).
+ pub const fn name(&self) -> &'static str {
+ match self {
+ TerminatorKind::Goto { .. } => "Goto",
+ TerminatorKind::SwitchInt { .. } => "SwitchInt",
+ TerminatorKind::Resume => "Resume",
+ TerminatorKind::Terminate => "Terminate",
+ TerminatorKind::Return => "Return",
+ TerminatorKind::Unreachable => "Unreachable",
+ TerminatorKind::Drop { .. } => "Drop",
+ TerminatorKind::Call { .. } => "Call",
+ TerminatorKind::Assert { .. } => "Assert",
+ TerminatorKind::Yield { .. } => "Yield",
+ TerminatorKind::GeneratorDrop => "GeneratorDrop",
+ TerminatorKind::FalseEdge { .. } => "FalseEdge",
+ TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
+ TerminatorKind::InlineAsm { .. } => "InlineAsm",
+ }
+ }
+}
+
/// Action to be taken when a stack unwind happens.
#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
#[derive(TypeFoldable, TypeVisitable)]
@@ -1002,7 +1028,7 @@ pub type PlaceElem<'tcx> = ProjectionElem<Local, Ty<'tcx>>;
/// This is what is implemented in miri today. Are these the semantics we want for MIR? Is this
/// something we can even decide without knowing more about Rust's memory model?
///
-/// **Needs clarifiation:** Is loading a place that has its variant index set well-formed? Miri
+/// **Needs clarification:** Is loading a place that has its variant index set well-formed? Miri
/// currently implements it, but it seems like this may be something to check against in the
/// validator.
#[derive(Clone, PartialEq, TyEncodable, TyDecodable, Hash, HashStable, TypeFoldable, TypeVisitable)]
@@ -1120,7 +1146,7 @@ pub enum Rvalue<'tcx> {
CheckedBinaryOp(BinOp, Box<(Operand<'tcx>, Operand<'tcx>)>),
/// Computes a value as described by the operation.
- NullaryOp(NullOp, Ty<'tcx>),
+ NullaryOp(NullOp<'tcx>, Ty<'tcx>),
/// Exactly like `BinaryOp`, but less operands.
///
@@ -1216,12 +1242,14 @@ pub enum AggregateKind<'tcx> {
Generator(DefId, SubstsRef<'tcx>, hir::Movability),
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
-pub enum NullOp {
+#[derive(Clone, Debug, PartialEq, Eq, TyEncodable, TyDecodable, Hash, HashStable)]
+pub enum NullOp<'tcx> {
/// Returns the size of a value of that type
SizeOf,
/// Returns the minimum alignment of a type
AlignOf,
+ /// Returns the offset of a field
+ OffsetOf(&'tcx List<FieldIdx>),
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs
index 4f00abf7f..5ca824134 100644
--- a/compiler/rustc_middle/src/mir/tcx.rs
+++ b/compiler/rustc_middle/src/mir/tcx.rs
@@ -188,7 +188,9 @@ impl<'tcx> Rvalue<'tcx> {
}
Rvalue::UnaryOp(UnOp::Not | UnOp::Neg, ref operand) => operand.ty(local_decls, tcx),
Rvalue::Discriminant(ref place) => place.ty(local_decls, tcx).ty.discriminant_ty(tcx),
- Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => tcx.types.usize,
+ Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {
+ tcx.types.usize
+ }
Rvalue::Aggregate(ref ak, ref ops) => match **ak {
AggregateKind::Array(ty) => tcx.mk_array(ty, ops.len() as u64),
AggregateKind::Tuple => {
diff --git a/compiler/rustc_middle/src/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs
index 988158321..06874741b 100644
--- a/compiler/rustc_middle/src/mir/type_foldable.rs
+++ b/compiler/rustc_middle/src/mir/type_foldable.rs
@@ -16,7 +16,6 @@ TrivialTypeTraversalAndLiftImpls! {
UserTypeAnnotationIndex,
BorrowKind,
CastKind,
- NullOp,
hir::Movability,
BasicBlock,
SwitchTargets,
@@ -25,9 +24,8 @@ TrivialTypeTraversalAndLiftImpls! {
}
TrivialTypeTraversalImpls! {
- for <'tcx> {
- ConstValue<'tcx>,
- }
+ ConstValue<'tcx>,
+ NullOp<'tcx>,
}
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx [InlineAsmTemplatePiece] {
diff --git a/compiler/rustc_middle/src/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs
index caa5edc32..8d44e929a 100644
--- a/compiler/rustc_middle/src/mir/visit.rs
+++ b/compiler/rustc_middle/src/mir/visit.rs
@@ -64,7 +64,7 @@
use crate::mir::*;
use crate::ty::subst::SubstsRef;
-use crate::ty::{CanonicalUserTypeAnnotation, Ty};
+use crate::ty::{self, CanonicalUserTypeAnnotation, Ty};
use rustc_span::Span;
macro_rules! make_mir_visitor {
@@ -192,6 +192,14 @@ macro_rules! make_mir_visitor {
self.super_constant(constant, location);
}
+ fn visit_ty_const(
+ &mut self,
+ ct: $( & $mutability)? ty::Const<'tcx>,
+ location: Location,
+ ) {
+ self.super_ty_const(ct, location);
+ }
+
fn visit_span(
&mut self,
span: $(& $mutability)? Span,
@@ -410,7 +418,7 @@ macro_rules! make_mir_visitor {
StatementKind::PlaceMention(place) => {
self.visit_place(
place,
- PlaceContext::NonUse(NonUseContext::PlaceMention),
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::PlaceMention),
location
);
}
@@ -496,6 +504,7 @@ macro_rules! make_mir_visitor {
place,
target: _,
unwind: _,
+ replace: _,
} => {
self.visit_place(
place,
@@ -625,8 +634,9 @@ macro_rules! make_mir_visitor {
self.visit_operand(operand, location);
}
- Rvalue::Repeat(value, _) => {
+ Rvalue::Repeat(value, ct) => {
self.visit_operand(value, location);
+ self.visit_ty_const($(&$mutability)? *ct, location);
}
Rvalue::ThreadLocalRef(_) => {}
@@ -773,12 +783,12 @@ macro_rules! make_mir_visitor {
fn super_ascribe_user_ty(&mut self,
place: & $($mutability)? Place<'tcx>,
- _variance: $(& $mutability)? ty::Variance,
+ variance: $(& $mutability)? ty::Variance,
user_ty: & $($mutability)? UserTypeProjection,
location: Location) {
self.visit_place(
place,
- PlaceContext::NonUse(NonUseContext::AscribeUserTy),
+ PlaceContext::NonUse(NonUseContext::AscribeUserTy($(* &$mutability *)? variance)),
location
);
self.visit_user_type_projection(user_ty);
@@ -833,6 +843,7 @@ macro_rules! make_mir_visitor {
source_info,
value,
argument_index: _,
+ references: _,
} = var_debug_info;
self.visit_source_info(source_info);
@@ -871,19 +882,26 @@ macro_rules! make_mir_visitor {
) {
let Constant {
span,
- user_ty,
+ user_ty: _, // no visit method for this
literal,
} = constant;
self.visit_span($(& $mutability)? *span);
- drop(user_ty); // no visit method for this
match literal {
- ConstantKind::Ty(_) => {}
+ ConstantKind::Ty(ct) => self.visit_ty_const($(&$mutability)? *ct, location),
ConstantKind::Val(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
ConstantKind::Unevaluated(_, ty) => self.visit_ty($(& $mutability)? *ty, TyContext::Location(location)),
}
}
+ fn super_ty_const(
+ &mut self,
+ _ct: $(& $mutability)? ty::Const<'tcx>,
+ _location: Location,
+ ) {
+
+ }
+
fn super_span(&mut self, _span: $(& $mutability)? Span) {
}
@@ -1249,6 +1267,11 @@ pub enum NonMutatingUseContext {
ShallowBorrow,
/// AddressOf for *const pointer.
AddressOf,
+ /// PlaceMention statement.
+ ///
+ /// This statement is executed as a check that the `Place` is live without reading from it,
+ /// so it must be considered as a non-mutating use.
+ PlaceMention,
/// Used as base for another place, e.g., `x` in `x.y`. Will not mutate the place.
/// For example, the projection `x.y` is not marked as a mutation in these cases:
/// ```ignore (illustrative)
@@ -1296,11 +1319,9 @@ pub enum NonUseContext {
/// Ending a storage live range.
StorageDead,
/// User type annotation assertions for NLL.
- AscribeUserTy,
+ AscribeUserTy(ty::Variance),
/// The data of a user variable, for debug info.
VarDebugInfo,
- /// PlaceMention statement.
- PlaceMention,
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
diff --git a/compiler/rustc_middle/src/query/erase.rs b/compiler/rustc_middle/src/query/erase.rs
index 7d9aea022..fd02a1613 100644
--- a/compiler/rustc_middle/src/query/erase.rs
+++ b/compiler/rustc_middle/src/query/erase.rs
@@ -28,7 +28,7 @@ pub fn erase<T: EraseType>(src: T) -> Erase<T> {
};
Erased::<<T as EraseType>::Result> {
- // SAFETY: Is it safe to transmute to MaybeUninit for types with the same sizes.
+ // SAFETY: It is safe to transmute to MaybeUninit for types with the same sizes.
data: unsafe { transmute_copy(&src) },
}
}
@@ -82,9 +82,10 @@ impl EraseType for Result<Option<ty::Instance<'_>>, rustc_errors::ErrorGuarantee
[u8; size_of::<Result<Option<ty::Instance<'static>>, rustc_errors::ErrorGuaranteed>>()];
}
-impl EraseType for Result<Option<ty::Const<'_>>, rustc_errors::ErrorGuaranteed> {
- type Result =
- [u8; size_of::<Result<Option<ty::Const<'static>>, rustc_errors::ErrorGuaranteed>>()];
+impl EraseType for Result<Option<ty::EarlyBinder<ty::Const<'_>>>, rustc_errors::ErrorGuaranteed> {
+ type Result = [u8; size_of::<
+ Result<Option<ty::EarlyBinder<ty::Const<'static>>>, rustc_errors::ErrorGuaranteed>,
+ >()];
}
impl EraseType for Result<ty::GenericArg<'_>, traits::query::NoSolution> {
@@ -171,6 +172,10 @@ impl EraseType for ty::Binder<'_, ty::FnSig<'_>> {
type Result = [u8; size_of::<ty::Binder<'static, ty::FnSig<'static>>>()];
}
+impl EraseType for ty::Binder<'_, &'_ ty::List<Ty<'_>>> {
+ type Result = [u8; size_of::<ty::Binder<'static, &'static ty::List<Ty<'static>>>>()];
+}
+
impl<T0, T1> EraseType for (&'_ T0, &'_ T1) {
type Result = [u8; size_of::<(&'static (), &'static ())>()];
}
diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs
index 23b28ac5c..fa62b7f32 100644
--- a/compiler/rustc_middle/src/query/keys.rs
+++ b/compiler/rustc_middle/src/query/keys.rs
@@ -174,14 +174,6 @@ impl AsLocalKey for DefId {
}
}
-impl Key for ty::WithOptConstParam<LocalDefId> {
- type CacheSelector = DefaultCacheSelector<Self>;
-
- fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
- self.did.default_span(tcx)
- }
-}
-
impl Key for SimplifiedType {
type CacheSelector = DefaultCacheSelector<Self>;
@@ -313,7 +305,7 @@ impl<'tcx> Key for (ty::UnevaluatedConst<'tcx>, ty::UnevaluatedConst<'tcx>) {
type CacheSelector = DefaultCacheSelector<Self>;
fn default_span(&self, tcx: TyCtxt<'_>) -> Span {
- (self.0).def.did.default_span(tcx)
+ (self.0).def.default_span(tcx)
}
}
diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs
index 7a5a16035..1528be42f 100644
--- a/compiler/rustc_middle/src/query/mod.rs
+++ b/compiler/rustc_middle/src/query/mod.rs
@@ -4,12 +4,98 @@
//! ["Queries: demand-driven compilation"](https://rustc-dev-guide.rust-lang.org/query.html).
//! This chapter includes instructions for adding new queries.
-use crate::ty::{self, print::describe_as_module, TyCtxt};
+#![allow(unused_parens)]
+
+use crate::dep_graph;
+use crate::dep_graph::DepKind;
+use crate::infer::canonical::{self, Canonical};
+use crate::lint::LintExpectation;
+use crate::metadata::ModChild;
+use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
+use crate::middle::debugger_visualizer::DebuggerVisualizerFile;
+use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
+use crate::middle::lib_features::LibFeatures;
+use crate::middle::privacy::EffectiveVisibilities;
+use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
+use crate::middle::stability::{self, DeprecationEntry};
+use crate::mir;
+use crate::mir::interpret::GlobalId;
+use crate::mir::interpret::{
+ ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
+};
+use crate::mir::interpret::{LitToConstError, LitToConstInput};
+use crate::mir::mono::CodegenUnit;
+use crate::query::erase::{erase, restore, Erase};
+use crate::query::plumbing::{query_ensure, query_get_at, DynamicQuery};
+use crate::thir;
+use crate::traits::query::{
+ CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
+ CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
+ CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
+};
+use crate::traits::query::{
+ DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult,
+ OutlivesBound,
+};
+use crate::traits::specialization_graph;
+use crate::traits::{
+ CanonicalChalkEnvironmentAndGoal, CodegenObligationError, EvaluationResult, ImplSource,
+ ObjectSafetyViolation, ObligationCause, OverflowError, WellFormedLoc,
+};
+use crate::ty::fast_reject::SimplifiedType;
+use crate::ty::layout::ValidityRequirement;
+use crate::ty::subst::{GenericArg, SubstsRef};
+use crate::ty::util::AlwaysRequiresDrop;
+use crate::ty::GeneratorDiagnosticData;
+use crate::ty::TyCtxtFeed;
+use crate::ty::{
+ self, print::describe_as_module, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt,
+ UnusedGenericParams,
+};
+use rustc_arena::TypedArena;
+use rustc_ast as ast;
+use rustc_ast::expand::allocator::AllocatorKind;
+use rustc_attr as attr;
+use rustc_data_structures::fingerprint::Fingerprint;
+use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
+use rustc_data_structures::steal::Steal;
+use rustc_data_structures::svh::Svh;
+use rustc_data_structures::sync::Lrc;
+use rustc_data_structures::sync::WorkerLocal;
+use rustc_data_structures::unord::UnordSet;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir as hir;
+use rustc_hir::def::{DefKind, DocLinkResMap};
+use rustc_hir::def_id::{
+ CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet,
+};
+use rustc_hir::lang_items::{LangItem, LanguageItems};
+use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
+use rustc_index::IndexVec;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_query_system::query::{try_get_cached, CacheSelector, QueryCache, QueryMode, QueryState};
+use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
+use rustc_session::cstore::{CrateDepKind, CrateSource};
+use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
+use rustc_session::lint::LintExpectationId;
+use rustc_session::Limits;
use rustc_span::def_id::LOCAL_CRATE;
+use rustc_span::symbol::Symbol;
+use rustc_span::{Span, DUMMY_SP};
+use rustc_target::abi;
+use rustc_target::spec::PanicStrategy;
+use std::mem;
+use std::ops::Deref;
+use std::path::PathBuf;
+use std::sync::Arc;
pub mod erase;
mod keys;
pub use keys::{AsLocalKey, Key, LocalCrate};
+pub mod on_disk_cache;
+#[macro_use]
+pub mod plumbing;
+pub use plumbing::{IntoQueryParam, TyCtxtAt, TyCtxtEnsure, TyCtxtEnsureWithValue};
// Each of these queries corresponds to a function pointer field in the
// `Providers` struct for requesting a value of that type, and a method
@@ -83,7 +169,7 @@ rustc_queries! {
/// Avoid calling this query directly.
query hir_module_items(key: LocalDefId) -> &'tcx rustc_middle::hir::ModuleItems {
arena_cache
- desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR module items in `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -92,14 +178,14 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner(key: hir::OwnerId) -> Option<crate::hir::Owner<'tcx>> {
- desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner of `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR ID for the given `LocalDefId` owner `key` if any.
///
/// Definitions that were generated with no HIR, would be fed to return `None`.
query opt_local_def_id_to_hir_id(key: LocalDefId) -> Option<hir::HirId>{
- desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR ID of `{}`", tcx.def_path_str(key) }
feedable
}
@@ -108,7 +194,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_parent(key: hir::OwnerId) -> hir::HirId {
- desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR parent of `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR nodes and bodies inside the HIR owner `key`.
@@ -116,7 +202,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_owner_nodes(key: hir::OwnerId) -> hir::MaybeOwner<&'tcx hir::OwnerNodes<'tcx>> {
- desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner items in `{}`", tcx.def_path_str(key) }
}
/// Gives access to the HIR attributes inside the HIR owner `key`.
@@ -124,30 +210,7 @@ rustc_queries! {
/// This can be conveniently accessed by methods on `tcx.hir()`.
/// Avoid calling this query directly.
query hir_attrs(key: hir::OwnerId) -> &'tcx hir::AttributeMap<'tcx> {
- desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key.to_def_id()) }
- }
-
- /// Computes the `DefId` of the corresponding const parameter in case the `key` is a
- /// const argument and returns `None` otherwise.
- ///
- /// ```ignore (incomplete)
- /// let a = foo::<7>();
- /// // ^ Calling `opt_const_param_of` for this argument,
- ///
- /// fn foo<const N: usize>()
- /// // ^ returns this `DefId`.
- ///
- /// fn bar() {
- /// // ^ While calling `opt_const_param_of` for other bodies returns `None`.
- /// }
- /// ```
- // It looks like caching this query on disk actually slightly
- // worsened performance in #74376.
- //
- // Once const generics are more prevalently used, we might want to
- // consider only caching calls returning `Some`.
- query opt_const_param_of(key: LocalDefId) -> Option<DefId> {
- desc { |tcx| "computing the optional const parameter of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting HIR owner attributes in `{}`", tcx.def_path_str(key) }
}
/// Given the def_id of a const-generic parameter, computes the associated default const
@@ -181,7 +244,7 @@ rustc_queries! {
}
query collect_return_position_impl_trait_in_trait_tys(key: DefId)
- -> Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>
+ -> Result<&'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>, ErrorGuaranteed>
{
desc { "comparing an impl and trait method signature, inferring any hidden `impl Trait` types in the process" }
cache_on_disk_if { key.is_local() }
@@ -258,6 +321,15 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
}
+ query opaque_types_defined_by(
+ key: LocalDefId
+ ) -> &'tcx [LocalDefId] {
+ desc {
+ |tcx| "computing the opaque types defined by `{}`",
+ tcx.def_path_str(key.to_def_id())
+ }
+ }
+
/// Returns the list of bounds that can be used for
/// `SelectionCandidate::ProjectionCandidate(_)` and
/// `ProjectionTyCandidate::TraitDef`.
@@ -274,7 +346,7 @@ rustc_queries! {
/// `key` is the `DefId` of the associated type or opaque type.
///
/// Bounds from the parent (e.g. with nested impl trait) are not included.
- query explicit_item_bounds(key: DefId) -> &'tcx [(ty::Predicate<'tcx>, Span)] {
+ query explicit_item_bounds(key: DefId) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, Span)]> {
desc { |tcx| "finding item bounds for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
@@ -318,7 +390,7 @@ rustc_queries! {
query shallow_lint_levels_on(key: hir::OwnerId) -> &'tcx rustc_middle::lint::ShallowLintLevelMap {
eval_always // fetches `resolutions`
arena_cache
- desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "looking up lint levels for `{}`", tcx.def_path_str(key) }
}
query lint_expectations(_: ()) -> &'tcx Vec<(LintExpectationId, LintExpectation)> {
@@ -328,7 +400,7 @@ rustc_queries! {
query parent_module_from_def_id(key: LocalDefId) -> LocalDefId {
eval_always
- desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "getting the parent module of `{}`", tcx.def_path_str(key) }
}
query expn_that_defined(key: DefId) -> rustc_span::ExpnId {
@@ -344,7 +416,7 @@ rustc_queries! {
/// Checks whether a type is representable or infinitely sized
query representability(_: LocalDefId) -> rustc_middle::ty::Representability {
- desc { "checking if `{}` is representable", tcx.def_path_str(key.to_def_id()) }
+ desc { "checking if `{}` is representable", tcx.def_path_str(key) }
// infinitely sized types will cause a cycle
cycle_delay_bug
// we don't want recursive representability calls to be forced with
@@ -369,26 +441,24 @@ rustc_queries! {
}
/// Fetch the THIR for a given body. If typeck for that body failed, returns an empty `Thir`.
- query thir_body(key: ty::WithOptConstParam<LocalDefId>)
- -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed>
- {
+ query thir_body(key: LocalDefId) -> Result<(&'tcx Steal<thir::Thir<'tcx>>, thir::ExprId), ErrorGuaranteed> {
// Perf tests revealed that hashing THIR is inefficient (see #85729).
no_hash
- desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "building THIR for `{}`", tcx.def_path_str(key) }
}
/// Create a THIR tree for debugging.
- query thir_tree(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
+ query thir_tree(key: LocalDefId) -> &'tcx String {
no_hash
arena_cache
- desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "constructing THIR tree for `{}`", tcx.def_path_str(key) }
}
/// Create a list-like THIR representation for debugging.
- query thir_flat(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx String {
+ query thir_flat(key: LocalDefId) -> &'tcx String {
no_hash
arena_cache
- desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "constructing flat THIR representation for `{}`", tcx.def_path_str(key) }
}
/// Set of all the `DefId`s in this crate that have MIR associated with
@@ -407,59 +477,35 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
- query mir_const_qualif_const_arg(
- key: (LocalDefId, DefId)
- ) -> mir::ConstQualifs {
- desc {
- |tcx| "const checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Fetch the MIR for a given `DefId` right after it's built - this includes
/// unreachable code.
- query mir_built(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ query mir_built(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "building MIR for `{}`", tcx.def_path_str(key) }
}
/// Fetch the MIR for a given `DefId` up till the point where it is
/// ready for const qualification.
///
/// See the README for the `mir` module for details.
- query mir_const(key: ty::WithOptConstParam<LocalDefId>) -> &'tcx Steal<mir::Body<'tcx>> {
- desc {
- |tcx| "preparing {}`{}` for borrow checking",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
+ query mir_const(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
+ desc { |tcx| "preparing `{}` for borrow checking", tcx.def_path_str(key) }
no_hash
}
/// Try to build an abstract representation of the given constant.
query thir_abstract_const(
key: DefId
- ) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
+ ) -> Result<Option<ty::EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed> {
desc {
|tcx| "building an abstract representation for `{}`", tcx.def_path_str(key),
}
separate_provide_extern
}
- /// Try to build an abstract representation of the given constant.
- query thir_abstract_const_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> Result<Option<ty::Const<'tcx>>, ErrorGuaranteed> {
- desc {
- |tcx|
- "building an abstract representation for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
- query mir_drops_elaborated_and_const_checked(
- key: ty::WithOptConstParam<LocalDefId>
- ) -> &'tcx Steal<mir::Body<'tcx>> {
+ query mir_drops_elaborated_and_const_checked(key: LocalDefId) -> &'tcx Steal<mir::Body<'tcx>> {
no_hash
- desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key.did.to_def_id()) }
+ desc { |tcx| "elaborating drops for `{}`", tcx.def_path_str(key) }
}
query mir_for_ctfe(
@@ -470,34 +516,22 @@ rustc_queries! {
separate_provide_extern
}
- query mir_for_ctfe_of_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::Body<'tcx> {
- desc {
- |tcx| "caching MIR for CTFE of the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
-
- query mir_promoted(key: ty::WithOptConstParam<LocalDefId>) ->
- (
- &'tcx Steal<mir::Body<'tcx>>,
- &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
- ) {
+ query mir_promoted(key: LocalDefId) -> (
+ &'tcx Steal<mir::Body<'tcx>>,
+ &'tcx Steal<IndexVec<mir::Promoted, mir::Body<'tcx>>>
+ ) {
no_hash
- desc {
- |tcx| "processing MIR for {}`{}`",
- if key.const_param_did.is_some() { "the const argument " } else { "" },
- tcx.def_path_str(key.did.to_def_id()),
- }
+ desc { |tcx| "promoting constants in MIR for `{}`", tcx.def_path_str(key) }
}
query closure_typeinfo(key: LocalDefId) -> ty::ClosureTypeInfo<'tcx> {
desc {
|tcx| "finding symbols for captures of closure `{}`",
- tcx.def_path_str(key.to_def_id())
+ tcx.def_path_str(key)
}
}
- query mir_generator_witnesses(key: DefId) -> &'tcx mir::GeneratorLayout<'tcx> {
+ query mir_generator_witnesses(key: DefId) -> &'tcx Option<mir::GeneratorLayout<'tcx>> {
arena_cache
desc { |tcx| "generator witness types for `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
@@ -505,7 +539,7 @@ rustc_queries! {
}
query check_generator_obligations(key: LocalDefId) {
- desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "verify auto trait bounds for generator interior type `{}`", tcx.def_path_str(key) }
}
/// MIR after our optimization passes have run. This is MIR that is ready
@@ -544,14 +578,6 @@ rustc_queries! {
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
- query promoted_mir_of_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>> {
- desc {
- |tcx| "optimizing promoted MIR for the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
- }
/// Erases regions from `ty` to yield a new type.
/// Normally you would just use `tcx.erase_regions(value)`,
@@ -595,7 +621,7 @@ rustc_queries! {
/// `explicit_predicates_of` and `explicit_item_bounds` will then take
/// the appropriate subsets of the predicates here.
query trait_explicit_predicates_and_bounds(key: LocalDefId) -> ty::GenericPredicates<'tcx> {
- desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "computing explicit predicates of trait `{}`", tcx.def_path_str(key) }
}
/// Returns the predicates written explicitly by the user.
@@ -637,7 +663,7 @@ rustc_queries! {
/// returns the full set of predicates. If `Some<Ident>`, then the query returns only the
/// subset of super-predicates that reference traits that define the given associated type.
/// This is used to avoid cycles in resolving types like `T::Item`.
- query super_predicates_that_define_assoc_type(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
+ query super_predicates_that_define_assoc_item(key: (DefId, rustc_span::symbol::Ident)) -> ty::GenericPredicates<'tcx> {
desc { |tcx| "computing the super traits of `{}` with associated type name `{}`",
tcx.def_path_str(key.0),
key.1
@@ -685,13 +711,11 @@ rustc_queries! {
/// `is_const_fn` function. Consider using `is_const_fn` or `is_const_fn_raw` instead.
query constness(key: DefId) -> hir::Constness {
desc { |tcx| "checking if item is const: `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
separate_provide_extern
}
query asyncness(key: DefId) -> hir::IsAsync {
desc { |tcx| "checking if the function is async: `{}`", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
separate_provide_extern
}
@@ -706,17 +730,9 @@ rustc_queries! {
desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) }
}
- /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`).
- query is_foreign_item(key: DefId) -> bool {
- desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) }
- cache_on_disk_if { key.is_local() }
- separate_provide_extern
- }
-
/// Returns `Some(generator_kind)` if the node pointed to by `def_id` is a generator.
query generator_kind(def_id: DefId) -> Option<hir::GeneratorKind> {
desc { |tcx| "looking up generator kind of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
@@ -739,9 +755,10 @@ rustc_queries! {
desc { "computing the inferred outlives predicates for items in this crate" }
}
- /// Maps from an impl/trait `DefId` to a list of the `DefId`s of its items.
+ /// Maps from an impl/trait or struct/variant `DefId`
+ /// to a list of the `DefId`s of its associated items or fields.
query associated_item_def_ids(key: DefId) -> &'tcx [DefId] {
- desc { |tcx| "collecting associated items of `{}`", tcx.def_path_str(key) }
+ desc { |tcx| "collecting associated items or fields of `{}`", tcx.def_path_str(key) }
cache_on_disk_if { key.is_local() }
separate_provide_extern
}
@@ -814,7 +831,6 @@ rustc_queries! {
}
query impl_polarity(impl_id: DefId) -> ty::ImplPolarity {
desc { |tcx| "computing implementation polarity of `{}`", tcx.def_path_str(impl_id) }
- cache_on_disk_if { impl_id.is_local() }
separate_provide_extern
}
@@ -837,28 +853,16 @@ rustc_queries! {
/// The result of unsafety-checking this `LocalDefId`.
query unsafety_check_result(key: LocalDefId) -> &'tcx mir::UnsafetyCheckResult {
- desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
- query unsafety_check_result_for_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::UnsafetyCheckResult {
- desc {
- |tcx| "unsafety-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Unsafety-check this `LocalDefId` with THIR unsafeck. This should be
/// used with `-Zthir-unsafeck`.
query thir_check_unsafety(key: LocalDefId) {
- desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "unsafety-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
- query thir_check_unsafety_for_const_arg(key: (LocalDefId, DefId)) {
- desc {
- |tcx| "unsafety-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Returns the types assumed to be well formed while "inside" of the given item.
///
@@ -913,7 +917,7 @@ rustc_queries! {
desc { |tcx| "checking privacy in {}", describe_as_module(key, tcx) }
}
- query check_liveness(key: DefId) {
+ query check_liveness(key: LocalDefId) {
desc { |tcx| "checking liveness of variables in `{}`", tcx.def_path_str(key) }
}
@@ -952,29 +956,16 @@ rustc_queries! {
separate_provide_extern
}
- query typeck_item_bodies(_: ()) -> () {
- desc { "type-checking all item bodies" }
- }
-
query typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
- }
- query typeck_const_arg(
- key: (LocalDefId, DefId)
- ) -> &'tcx ty::TypeckResults<'tcx> {
- desc {
- |tcx| "type-checking the const argument `{}`",
- tcx.def_path_str(key.0.to_def_id()),
- }
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
+ cache_on_disk_if(tcx) { !tcx.is_typeck_child(key.to_def_id()) }
}
query diagnostic_only_typeck(key: LocalDefId) -> &'tcx ty::TypeckResults<'tcx> {
- desc { |tcx| "type-checking `{}`", tcx.def_path_str(key.to_def_id()) }
- cache_on_disk_if { true }
+ desc { |tcx| "type-checking `{}`", tcx.def_path_str(key) }
}
query used_trait_imports(key: LocalDefId) -> &'tcx UnordSet<LocalDefId> {
- desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "finding used_trait_imports `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -989,15 +980,9 @@ rustc_queries! {
/// Borrow-checks the function body. If this is a closure, returns
/// additional requirements that the closure's creator must verify.
query mir_borrowck(key: LocalDefId) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "borrow-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if(tcx) { tcx.is_typeck_child(key.to_def_id()) }
}
- query mir_borrowck_const_arg(key: (LocalDefId, DefId)) -> &'tcx mir::BorrowCheckResult<'tcx> {
- desc {
- |tcx| "borrow-checking the const argument`{}`",
- tcx.def_path_str(key.0.to_def_id())
- }
- }
/// Gets a complete map from all types to their inherent impls.
/// Not meant to be used directly outside of coherence.
@@ -1017,7 +1002,7 @@ rustc_queries! {
query orphan_check_impl(key: LocalDefId) -> Result<(), ErrorGuaranteed> {
desc { |tcx|
"checking whether impl `{}` follows the orphan rules",
- tcx.def_path_str(key.to_def_id()),
+ tcx.def_path_str(key),
}
}
@@ -1029,7 +1014,7 @@ rustc_queries! {
desc { |tcx|
"computing if `{}` (transitively) calls `{}`",
key.0,
- tcx.def_path_str(key.1.to_def_id()),
+ tcx.def_path_str(key.1),
}
}
@@ -1094,7 +1079,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> Option<mir::DestructuredConstant<'tcx>> {
desc { "destructuring MIR constant"}
- remap_env_constness
}
/// Dereference a constant reference or raw pointer and turn the result into a constant
@@ -1103,7 +1087,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, mir::ConstantKind<'tcx>>
) -> mir::ConstantKind<'tcx> {
desc { "dereferencing MIR constant" }
- remap_env_constness
}
query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> {
@@ -1121,8 +1104,8 @@ rustc_queries! {
desc { "converting literal to mir constant" }
}
- query check_match(key: LocalDefId) {
- desc { |tcx| "match-checking `{}`", tcx.def_path_str(key.to_def_id()) }
+ query check_match(key: LocalDefId) -> Result<(), rustc_errors::ErrorGuaranteed> {
+ desc { |tcx| "match-checking `{}`", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
@@ -1243,7 +1226,6 @@ rustc_queries! {
query fn_arg_names(def_id: DefId) -> &'tcx [rustc_span::symbol::Ident] {
desc { |tcx| "looking up function parameter names for `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
/// Gets the rendered value of the specified constant or associated constant.
@@ -1251,12 +1233,10 @@ rustc_queries! {
query rendered_const(def_id: DefId) -> &'tcx String {
arena_cache
desc { |tcx| "rendering constant initializer of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
query impl_parent(def_id: DefId) -> Option<DefId> {
desc { |tcx| "computing specialization parent impl of `{}`", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
}
@@ -1296,7 +1276,7 @@ rustc_queries! {
query codegen_select_candidate(
key: (ty::ParamEnv<'tcx>, ty::PolyTraitRef<'tcx>)
- ) -> Result<&'tcx ImplSource<'tcx, ()>, traits::CodegenObligationError> {
+ ) -> Result<&'tcx ImplSource<'tcx, ()>, CodegenObligationError> {
cache_on_disk_if { true }
desc { |tcx| "computing candidate for `{}`", key.1 }
}
@@ -1317,7 +1297,7 @@ rustc_queries! {
desc { |tcx| "building specialization graph of trait `{}`", tcx.def_path_str(trait_id) }
cache_on_disk_if { true }
}
- query object_safety_violations(trait_id: DefId) -> &'tcx [traits::ObjectSafetyViolation] {
+ query object_safety_violations(trait_id: DefId) -> &'tcx [ObjectSafetyViolation] {
desc { |tcx| "determining object safety of trait `{}`", tcx.def_path_str(trait_id) }
}
query check_is_object_safe(trait_id: DefId) -> bool {
@@ -1346,32 +1326,26 @@ rustc_queries! {
/// `ty.is_copy()`, etc, since that will prune the environment where possible.
query is_copy_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Copy`", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_sized`.
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Sized`", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_freeze`.
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is freeze", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_unpin`.
query is_unpin_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` is `Unpin`", env.value }
- remap_env_constness
}
/// Query backing `Ty::needs_drop`.
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` needs drop", env.value }
- remap_env_constness
}
/// Query backing `Ty::has_significant_drop_raw`.
query has_significant_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
desc { "computing whether `{}` has a significant drop", env.value }
- remap_env_constness
}
/// Query backing `Ty::is_structural_eq_shallow`.
@@ -1411,7 +1385,6 @@ rustc_queries! {
) -> Result<ty::layout::TyAndLayout<'tcx>, ty::layout::LayoutError<'tcx>> {
depth_limit
desc { "computing layout of `{}`", key.value }
- remap_env_constness
}
/// Compute a `FnAbi` suitable for indirect calls, i.e. to `fn` pointers.
@@ -1422,7 +1395,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::PolyFnSig<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}` function pointers", key.value.0 }
- remap_env_constness
}
/// Compute a `FnAbi` suitable for declaring/defining an `fn` instance, and for
@@ -1434,7 +1406,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (ty::Instance<'tcx>, &'tcx ty::List<Ty<'tcx>>)>
) -> Result<&'tcx abi::call::FnAbi<'tcx, Ty<'tcx>>, ty::layout::FnAbiError<'tcx>> {
desc { "computing call ABI of `{}`", key.value.0 }
- remap_env_constness
}
query dylib_dependency_formats(_: CrateNum)
@@ -1478,7 +1449,7 @@ rustc_queries! {
separate_provide_extern
}
query has_ffi_unwind_calls(key: LocalDefId) -> bool {
- desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "checking if `{}` contains FFI-unwind calls", tcx.def_path_str(key) }
cache_on_disk_if { true }
}
query required_panic_strategy(_: CrateNum) -> Option<PanicStrategy> {
@@ -1518,13 +1489,12 @@ rustc_queries! {
query impl_defaultness(def_id: DefId) -> hir::Defaultness {
desc { |tcx| "looking up whether `{}` is a default impl", tcx.def_path_str(def_id) }
- cache_on_disk_if { def_id.is_local() }
separate_provide_extern
feedable
}
query check_well_formed(key: hir::OwnerId) -> () {
- desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key.to_def_id()) }
+ desc { |tcx| "checking that `{}` is well-formed", tcx.def_path_str(key) }
}
// The `DefId`s of all non-generic functions and statics in the given crate
@@ -1553,7 +1523,7 @@ rustc_queries! {
query is_unreachable_local_definition(def_id: LocalDefId) -> bool {
desc { |tcx|
"checking whether `{}` is reachable from outside the crate",
- tcx.def_path_str(def_id.to_def_id()),
+ tcx.def_path_str(def_id),
}
}
@@ -1747,7 +1717,7 @@ rustc_queries! {
separate_provide_extern
}
query extern_mod_stmt_cnum(def_id: LocalDefId) -> Option<CrateNum> {
- desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ desc { |tcx| "computing crate imported by `{}`", tcx.def_path_str(def_id) }
}
query lib_features(_: ()) -> &'tcx LibFeatures {
@@ -1818,12 +1788,18 @@ rustc_queries! {
desc { "looking at the source for a crate" }
separate_provide_extern
}
+
/// Returns the debugger visualizers defined for this crate.
- query debugger_visualizers(_: CrateNum) -> &'tcx Vec<rustc_span::DebuggerVisualizerFile> {
+ /// NOTE: This query has to be marked `eval_always` because it reads data
+ /// directly from disk that is not tracked anywhere else. I.e. it
+ /// represents a genuine input to the query system.
+ query debugger_visualizers(_: CrateNum) -> &'tcx Vec<DebuggerVisualizerFile> {
arena_cache
desc { "looking up the debugger visualizers for this crate" }
separate_provide_extern
+ eval_always
}
+
query postorder_cnums(_: ()) -> &'tcx [CrateNum] {
eval_always
desc { "generating a postorder list of CrateNums" }
@@ -1851,7 +1827,7 @@ rustc_queries! {
desc { "fetching potentially unused trait imports" }
}
query names_imported_by_glob_use(def_id: LocalDefId) -> &'tcx UnordSet<Symbol> {
- desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id.to_def_id()) }
+ desc { |tcx| "finding names imported by glob use for `{}`", tcx.def_path_str(def_id) }
}
query stability_index(_: ()) -> &'tcx stability::Index {
@@ -1865,8 +1841,7 @@ rustc_queries! {
}
/// A list of all traits in a crate, used by rustdoc and error reporting.
- /// NOTE: Not named just `traits` due to a naming conflict.
- query traits_in_crate(_: CrateNum) -> &'tcx [DefId] {
+ query traits(_: CrateNum) -> &'tcx [DefId] {
desc { "fetching all traits in a crate" }
separate_provide_extern
}
@@ -1937,7 +1912,16 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{}`", goal.value.value }
- remap_env_constness
+ }
+
+ /// Do not call this query directly: invoke `normalize` instead.
+ query normalize_inherent_projection_ty(
+ goal: CanonicalProjectionGoal<'tcx>
+ ) -> Result<
+ &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, NormalizationResult<'tcx>>>,
+ NoSolution,
+ > {
+ desc { "normalizing `{}`", goal.value.value }
}
/// Do not call this query directly: invoke `try_normalize_erasing_regions` instead.
@@ -1945,7 +1929,6 @@ rustc_queries! {
goal: ParamEnvAnd<'tcx, GenericArg<'tcx>>
) -> Result<GenericArg<'tcx>, NoSolution> {
desc { "normalizing `{}`", goal.value }
- remap_env_constness
}
query implied_outlives_bounds(
@@ -1955,7 +1938,6 @@ rustc_queries! {
NoSolution,
> {
desc { "computing implied outlives bounds for `{}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly:
@@ -1967,19 +1949,18 @@ rustc_queries! {
NoSolution,
> {
desc { "computing dropck types for `{}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: invoke `infcx.predicate_may_hold()` or
/// `infcx.predicate_must_hold()` instead.
query evaluate_obligation(
goal: CanonicalPredicateGoal<'tcx>
- ) -> Result<traits::EvaluationResult, traits::OverflowError> {
+ ) -> Result<EvaluationResult, OverflowError> {
desc { "evaluating trait selection obligation `{}`", goal.value.value }
}
query evaluate_goal(
- goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx>
+ goal: CanonicalChalkEnvironmentAndGoal<'tcx>
) -> Result<
&'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>,
NoSolution
@@ -1995,7 +1976,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_ascribe_user_type` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Eq` type-op
@@ -2006,7 +1986,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_eq` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Subtype` type-op
@@ -2017,7 +1996,6 @@ rustc_queries! {
NoSolution,
> {
desc { "evaluating `type_op_subtype` `{:?}`", goal.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `ProvePredicate` type-op
@@ -2038,7 +2016,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2049,7 +2026,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2060,7 +2036,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
/// Do not call this query directly: part of the `Normalize` type-op
@@ -2071,7 +2046,6 @@ rustc_queries! {
NoSolution,
> {
desc { "normalizing `{:?}`", goal.value.value.value }
- remap_env_constness
}
query subst_and_check_impossible_predicates(key: (DefId, SubstsRef<'tcx>)) -> bool {
@@ -2093,7 +2067,6 @@ rustc_queries! {
goal: CanonicalTyGoal<'tcx>
) -> MethodAutoderefStepsResult<'tcx> {
desc { "computing autoderef types for `{}`", goal.value.value }
- remap_env_constness
}
query supported_target_features(_: CrateNum) -> &'tcx FxHashMap<String, Option<Symbol>> {
@@ -2138,17 +2111,6 @@ rustc_queries! {
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>
) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
desc { "resolving instance `{}`", ty::Instance::new(key.value.0, key.value.1) }
- remap_env_constness
- }
-
- query resolve_instance_of_const_arg(
- key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>
- ) -> Result<Option<ty::Instance<'tcx>>, ErrorGuaranteed> {
- desc {
- "resolving instance of the const argument `{}`",
- ty::Instance::new(key.value.0.to_def_id(), key.value.2),
- }
- remap_env_constness
}
query reveal_opaque_types_in_bounds(key: &'tcx ty::List<ty::Predicate<'tcx>>) -> &'tcx ty::List<ty::Predicate<'tcx>> {
@@ -2168,8 +2130,8 @@ rustc_queries! {
/// all of the cases that the normal `ty::Ty`-based wfcheck does. This is fine,
/// because the `ty::Ty`-based wfcheck is always run.
query diagnostic_hir_wf_check(
- key: (ty::Predicate<'tcx>, traits::WellFormedLoc)
- ) -> &'tcx Option<traits::ObligationCause<'tcx>> {
+ key: (ty::Predicate<'tcx>, WellFormedLoc)
+ ) -> &'tcx Option<ObligationCause<'tcx>> {
arena_cache
eval_always
no_hash
@@ -2197,7 +2159,7 @@ rustc_queries! {
query compare_impl_const(
key: (LocalDefId, DefId)
) -> Result<(), ErrorGuaranteed> {
- desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0.to_def_id()) }
+ desc { |tcx| "checking assoc const `{}` has the same type as trait item", tcx.def_path_str(key.0) }
}
query deduced_param_attrs(def_id: DefId) -> &'tcx [ty::DeducedParamAttrs] {
@@ -2224,3 +2186,6 @@ rustc_queries! {
desc { "check whether two const param are definitely not equal to eachother"}
}
}
+
+rustc_query_append! { define_callbacks! }
+rustc_feedable_queries! { define_feedable! }
diff --git a/compiler/rustc_query_impl/src/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs
index 30477c7bd..220118ae5 100644
--- a/compiler/rustc_query_impl/src/on_disk_cache.rs
+++ b/compiler/rustc_middle/src/query/on_disk_cache.rs
@@ -1,19 +1,18 @@
-use crate::QueryCtxt;
use rustc_data_structures::fx::{FxHashMap, FxIndexSet};
use rustc_data_structures::memmap::Mmap;
+use rustc_data_structures::stable_hasher::Hash64;
use rustc_data_structures::sync::{HashMapExt, Lock, Lrc, RwLock};
use rustc_data_structures::unhash::UnhashMap;
use rustc_data_structures::unord::UnordSet;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathHash;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::dep_graph::{DepNodeIndex, SerializedDepNodeIndex};
use rustc_middle::mir::interpret::{AllocDecodingSession, AllocDecodingState};
use rustc_middle::mir::{self, interpret};
use rustc_middle::ty::codec::{RefDecodable, TyDecoder, TyEncoder};
use rustc_middle::ty::{self, Ty, TyCtxt};
-use rustc_query_system::dep_graph::DepContext;
-use rustc_query_system::query::{QueryCache, QuerySideEffects};
+use rustc_query_system::query::QuerySideEffects;
use rustc_serialize::{
opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder},
Decodable, Decoder, Encodable, Encoder,
@@ -122,10 +121,12 @@ struct SourceFileIndex(u32);
pub struct AbsoluteBytePos(u64);
impl AbsoluteBytePos {
- fn new(pos: usize) -> AbsoluteBytePos {
+ #[inline]
+ pub fn new(pos: usize) -> AbsoluteBytePos {
AbsoluteBytePos(pos.try_into().expect("Incremental cache file size overflowed u64."))
}
+ #[inline]
fn to_usize(self) -> usize {
self.0 as usize
}
@@ -138,16 +139,18 @@ impl AbsoluteBytePos {
/// is the only thing available when decoding the cache's [Footer].
#[derive(Encodable, Decodable, Clone, Debug)]
struct EncodedSourceFileId {
- file_name_hash: u64,
+ file_name_hash: Hash64,
stable_crate_id: StableCrateId,
}
impl EncodedSourceFileId {
+ #[inline]
fn translate(&self, tcx: TyCtxt<'_>) -> StableSourceFileId {
let cnum = tcx.stable_crate_id_to_crate_num(self.stable_crate_id);
StableSourceFileId { file_name_hash: self.file_name_hash, cnum }
}
+ #[inline]
fn new(tcx: TyCtxt<'_>, file: &SourceFile) -> EncodedSourceFileId {
let source_file_id = StableSourceFileId::new(file);
EncodedSourceFileId {
@@ -157,9 +160,9 @@ impl EncodedSourceFileId {
}
}
-impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
+impl<'sess> OnDiskCache<'sess> {
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
- fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self {
+ pub fn new(sess: &'sess Session, data: Mmap, start_pos: usize) -> Self {
debug_assert!(sess.opts.incremental.is_some());
// Wrap in a scope so we can borrow `data`.
@@ -168,13 +171,12 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
// Decode the *position* of the footer, which can be found in the
// last 8 bytes of the file.
- decoder.set_position(data.len() - IntEncodedWithFixedSize::ENCODED_SIZE);
- let footer_pos = IntEncodedWithFixedSize::decode(&mut decoder).0 as usize;
-
+ let footer_pos = decoder
+ .with_position(decoder.len() - IntEncodedWithFixedSize::ENCODED_SIZE, |decoder| {
+ IntEncodedWithFixedSize::decode(decoder).0 as usize
+ });
// Decode the file footer, which contains all the lookup tables, etc.
- decoder.set_position(footer_pos);
-
- decode_tagged(&mut decoder, TAG_FILE_FOOTER)
+ decoder.with_position(footer_pos, |decoder| decode_tagged(decoder, TAG_FILE_FOOTER))
};
Self {
@@ -193,7 +195,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
}
}
- fn new_empty(source_map: &'sess SourceMap) -> Self {
+ pub fn new_empty(source_map: &'sess SourceMap) -> Self {
Self {
serialized_data: RwLock::new(None),
file_index_to_stable_id: Default::default(),
@@ -215,7 +217,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
/// Cache promotions require invoking queries, which needs to read the serialized data.
/// In order to serialize the new on-disk cache, the former on-disk cache file needs to be
/// deleted, hence we won't be able to refer to its memmapped data.
- fn drop_serialized_data(&self, tcx: TyCtxt<'_>) {
+ pub fn drop_serialized_data(&self, tcx: TyCtxt<'_>) {
// Load everything into memory so we can write it out to the on-disk
// cache. The vast majority of cacheable query results should already
// be in memory, so this should be a cheap operation.
@@ -227,7 +229,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
*self.serialized_data.write() = None;
}
- fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
+ pub fn serialize(&self, tcx: TyCtxt<'_>, encoder: FileEncoder) -> FileEncodeResult {
// Serializing the `DepGraph` should not modify it.
tcx.dep_graph.with_ignore(|| {
// Allocate `SourceFileIndex`es.
@@ -269,7 +271,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
tcx.sess.time("encode_query_results", || {
let enc = &mut encoder;
let qri = &mut query_result_index;
- QueryCtxt::from_tcx(tcx).encode_query_results(enc, qri);
+ (tcx.query_system.fns.encode_query_results)(tcx, enc, qri);
});
// Encode side effects.
@@ -299,7 +301,7 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
interpret_alloc_index.reserve(new_n - n);
for idx in n..new_n {
let id = encoder.interpret_allocs[idx];
- let pos = encoder.position() as u32;
+ let pos: u32 = encoder.position().try_into().unwrap();
interpret_alloc_index.push(pos);
interpret::specialized_encode_alloc_id(&mut encoder, tcx, id);
}
@@ -358,12 +360,6 @@ impl<'sess> rustc_middle::ty::OnDiskCache<'sess> for OnDiskCache<'sess> {
encoder.finish()
})
}
-}
-
-impl<'sess> OnDiskCache<'sess> {
- pub fn as_dyn(&self) -> &dyn rustc_middle::ty::OnDiskCache<'sess> {
- self as _
- }
/// Loads a `QuerySideEffects` created during the previous compilation session.
pub fn load_side_effects(
@@ -380,8 +376,6 @@ impl<'sess> OnDiskCache<'sess> {
/// Stores a `QuerySideEffects` emitted during the current compilation session.
/// Anything stored like this will be available via `load_side_effects` in
/// the next compilation session.
- #[inline(never)]
- #[cold]
pub fn store_side_effects(&self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
let mut current_side_effects = self.current_side_effects.borrow_mut();
let prev = current_side_effects.insert(dep_node_index, side_effects);
@@ -389,6 +383,7 @@ impl<'sess> OnDiskCache<'sess> {
}
/// Return whether the cached query result can be decoded.
+ #[inline]
pub fn loadable_from_disk(&self, dep_node_index: SerializedDepNodeIndex) -> bool {
self.query_result_index.contains_key(&dep_node_index)
// with_decoder is infallible, so we can stop here
@@ -413,8 +408,6 @@ impl<'sess> OnDiskCache<'sess> {
/// Since many anonymous queries can share the same `DepNode`, we aggregate
/// them -- as opposed to regular queries where we assume that there is a
/// 1:1 relationship between query-key and `DepNode`.
- #[inline(never)]
- #[cold]
pub fn store_side_effects_for_anon_node(
&self,
dep_node_index: DepNodeIndex,
@@ -485,6 +478,7 @@ pub struct CacheDecoder<'a, 'tcx> {
}
impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
+ #[inline]
fn file_index_to_file(&self, index: SourceFileIndex) -> Lrc<SourceFile> {
let CacheDecoder {
tcx,
@@ -521,29 +515,13 @@ impl<'a, 'tcx> CacheDecoder<'a, 'tcx> {
}
}
-trait DecoderWithPosition: Decoder {
- fn position(&self) -> usize;
-}
-
-impl<'a> DecoderWithPosition for MemDecoder<'a> {
- fn position(&self) -> usize {
- self.position()
- }
-}
-
-impl<'a, 'tcx> DecoderWithPosition for CacheDecoder<'a, 'tcx> {
- fn position(&self) -> usize {
- self.opaque.position()
- }
-}
-
// Decodes something that was encoded with `encode_tagged()` and verify that the
// tag matches and the correct amount of bytes was read.
fn decode_tagged<D, T, V>(decoder: &mut D, expected_tag: T) -> V
where
T: Decodable<D> + Eq + std::fmt::Debug,
V: Decodable<D>,
- D: DecoderWithPosition,
+ D: Decoder,
{
let start_pos = decoder.position();
@@ -567,16 +545,6 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
self.tcx
}
- #[inline]
- fn position(&self) -> usize {
- self.opaque.position()
- }
-
- #[inline]
- fn peek_byte(&self) -> u8 {
- self.opaque.data[self.opaque.position()]
- }
-
fn cached_ty_for_shorthand<F>(&mut self, shorthand: usize, or_insert_with: F) -> Ty<'tcx>
where
F: FnOnce(&mut Self) -> Ty<'tcx>,
@@ -599,9 +567,9 @@ impl<'a, 'tcx> TyDecoder for CacheDecoder<'a, 'tcx> {
where
F: FnOnce(&mut Self) -> R,
{
- debug_assert!(pos < self.opaque.data.len());
+ debug_assert!(pos < self.opaque.len());
- let new_opaque = MemDecoder::new(self.opaque.data, pos);
+ let new_opaque = MemDecoder::new(self.opaque.data(), pos);
let old_opaque = mem::replace(&mut self.opaque, new_opaque);
let r = f(self);
self.opaque = old_opaque;
@@ -667,7 +635,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for ExpnId {
#[cfg(debug_assertions)]
{
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
- let local_hash: u64 = decoder.tcx.with_stable_hashing_context(|mut hcx| {
+ let local_hash = decoder.tcx.with_stable_hashing_context(|mut hcx| {
let mut hasher = StableHasher::new();
expn_id.expn_data().hash_stable(&mut hcx, &mut hasher);
hasher.finish()
@@ -731,6 +699,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Span {
// copy&paste impl from rustc_metadata
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
let tag = d.read_u8();
@@ -742,17 +711,12 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol {
SYMBOL_OFFSET => {
// read str offset
let pos = d.read_usize();
- let old_pos = d.opaque.position();
-
- // move to str ofset and read
- d.opaque.set_position(pos);
- let s = d.read_str();
- let sym = Symbol::intern(s);
-
- // restore position
- d.opaque.set_position(old_pos);
- sym
+ // move to str offset and read
+ d.opaque.with_position(pos, |d| {
+ let s = d.read_str();
+ Symbol::intern(s)
+ })
}
SYMBOL_PREINTERNED => {
let symbol_index = d.read_u32();
@@ -764,6 +728,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for Symbol {
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for CrateNum {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
let stable_id = StableCrateId::decode(d);
let cnum = d.tcx.stable_crate_id_to_crate_num(stable_id);
@@ -785,6 +750,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefIndex {
// compilation sessions. We use the `DefPathHash`, which is stable across
// sessions, to map the old `DefId` to the new one.
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
// Load the `DefPathHash` which is was we encoded the `DefId` as.
let def_path_hash = DefPathHash::decode(d);
@@ -801,12 +767,16 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for DefId {
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx UnordSet<LocalDefId> {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
-impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'tcx>> {
+impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
+ for &'tcx FxHashMap<DefId, ty::EarlyBinder<Ty<'tcx>>>
+{
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
@@ -815,24 +785,28 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx FxHashMap<DefId, Ty<'
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>>
for &'tcx IndexVec<mir::Promoted, mir::Body<'tcx>>
{
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Predicate<'tcx>, Span)] {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [(ty::Clause<'tcx>, Span)] {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
}
impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsmTemplatePiece] {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Self {
RefDecodable::decode(d)
}
@@ -841,6 +815,7 @@ impl<'a, 'tcx> Decodable<CacheDecoder<'a, 'tcx>> for &'tcx [rustc_ast::InlineAsm
macro_rules! impl_ref_decoder {
(<$tcx:tt> $($ty:ty,)*) => {
$(impl<'a, $tcx> Decodable<CacheDecoder<'a, $tcx>> for &$tcx [$ty] {
+ #[inline]
fn decode(d: &mut CacheDecoder<'a, $tcx>) -> Self {
RefDecodable::decode(d)
}
@@ -875,6 +850,7 @@ pub struct CacheEncoder<'a, 'tcx> {
}
impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
+ #[inline]
fn source_file_index(&mut self, source_file: Lrc<SourceFile>) -> SourceFileIndex {
self.file_to_file_index[&(&*source_file as *const SourceFile)]
}
@@ -884,7 +860,7 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
/// encode the specified tag, then the given value, then the number of
/// bytes taken up by tag and value. On decoding, we can then verify that
/// we get the expected tag and read the expected number of bytes.
- fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(&mut self, tag: T, value: &V) {
+ pub fn encode_tagged<T: Encodable<Self>, V: Encodable<Self>>(&mut self, tag: T, value: &V) {
let start_pos = self.position();
tag.encode(self);
@@ -894,6 +870,7 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> {
((end_pos - start_pos) as u64).encode(self);
}
+ #[inline]
fn finish(self) -> Result<usize, io::Error> {
self.encoder.finish()
}
@@ -986,15 +963,19 @@ impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> {
type I = TyCtxt<'tcx>;
const CLEAR_CROSS_CRATE: bool = false;
+ #[inline]
fn position(&self) -> usize {
self.encoder.position()
}
+ #[inline]
fn type_shorthands(&mut self) -> &mut FxHashMap<Ty<'tcx>, usize> {
&mut self.type_shorthands
}
+ #[inline]
fn predicate_shorthands(&mut self) -> &mut FxHashMap<ty::PredicateKind<'tcx>, usize> {
&mut self.predicate_shorthands
}
+ #[inline]
fn encode_alloc_id(&mut self, alloc_id: &interpret::AllocId) {
let (index, _) = self.interpret_allocs.insert_full(*alloc_id);
@@ -1003,12 +984,14 @@ impl<'a, 'tcx> TyEncoder for CacheEncoder<'a, 'tcx> {
}
impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for CrateNum {
+ #[inline]
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
s.tcx.stable_crate_id(*self).encode(s);
}
}
impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for DefId {
+ #[inline]
fn encode(&self, s: &mut CacheEncoder<'a, 'tcx>) {
s.tcx.def_path_hash(*self).encode(s);
}
@@ -1043,11 +1026,7 @@ impl<'a, 'tcx> Encoder for CacheEncoder<'a, 'tcx> {
emit_i64(i64);
emit_i32(i32);
emit_i16(i16);
- emit_i8(i8);
- emit_bool(bool);
- emit_char(char);
- emit_str(&str);
emit_raw_bytes(&[u8]);
}
}
@@ -1061,33 +1040,3 @@ impl<'a, 'tcx> Encodable<CacheEncoder<'a, 'tcx>> for [u8] {
self.encode(&mut e.encoder);
}
}
-
-pub(crate) fn encode_query_results<'a, 'tcx, Q>(
- query: Q,
- qcx: QueryCtxt<'tcx>,
- encoder: &mut CacheEncoder<'a, 'tcx>,
- query_result_index: &mut EncodedDepNodeIndex,
-) where
- Q: super::QueryConfigRestored<'tcx>,
- Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
-{
- let _timer = qcx
- .tcx
- .profiler()
- .verbose_generic_activity_with_arg("encode_query_results_for", query.name());
-
- assert!(query.query_state(qcx).all_inactive());
- let cache = query.query_cache(qcx);
- cache.iter(&mut |key, value, dep_node| {
- if query.cache_on_disk(qcx.tcx, &key) {
- let dep_node = SerializedDepNodeIndex::new(dep_node.index());
-
- // Record position of the cache entry.
- query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.encoder.position())));
-
- // Encode the type check tables with the `SerializedDepNodeIndex`
- // as tag.
- encoder.encode_tagged(dep_node, &Q::restore(*value));
- }
- });
-}
diff --git a/compiler/rustc_middle/src/ty/query.rs b/compiler/rustc_middle/src/query/plumbing.rs
index fa9fea723..97edfc2fc 100644
--- a/compiler/rustc_middle/src/ty/query.rs
+++ b/compiler/rustc_middle/src/query/plumbing.rs
@@ -1,87 +1,88 @@
-#![allow(unused_parens)]
-
use crate::dep_graph;
-use crate::infer::canonical::{self, Canonical};
-use crate::lint::LintExpectation;
-use crate::metadata::ModChild;
-use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
-use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
-use crate::middle::lib_features::LibFeatures;
-use crate::middle::privacy::EffectiveVisibilities;
-use crate::middle::resolve_bound_vars::{ObjectLifetimeDefault, ResolveBoundVars, ResolvedArg};
-use crate::middle::stability::{self, DeprecationEntry};
-use crate::mir;
-use crate::mir::interpret::GlobalId;
-use crate::mir::interpret::{
- ConstValue, EvalToAllocationRawResult, EvalToConstValueResult, EvalToValTreeResult,
-};
-use crate::mir::interpret::{LitToConstError, LitToConstInput};
-use crate::mir::mono::CodegenUnit;
-use crate::query::erase::{erase, restore, Erase};
-use crate::query::{AsLocalKey, Key};
-use crate::thir;
-use crate::traits::query::{
- CanonicalPredicateGoal, CanonicalProjectionGoal, CanonicalTyGoal,
- CanonicalTypeOpAscribeUserTypeGoal, CanonicalTypeOpEqGoal, CanonicalTypeOpNormalizeGoal,
- CanonicalTypeOpProvePredicateGoal, CanonicalTypeOpSubtypeGoal, NoSolution,
-};
-use crate::traits::query::{
- DropckConstraint, DropckOutlivesResult, MethodAutoderefStepsResult, NormalizationResult,
- OutlivesBound,
-};
-use crate::traits::specialization_graph;
-use crate::traits::{self, ImplSource};
-use crate::ty::context::TyCtxtFeed;
-use crate::ty::fast_reject::SimplifiedType;
-use crate::ty::layout::ValidityRequirement;
-use crate::ty::subst::{GenericArg, SubstsRef};
-use crate::ty::util::AlwaysRequiresDrop;
-use crate::ty::GeneratorDiagnosticData;
-use crate::ty::{self, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt, UnusedGenericParams};
-use rustc_arena::TypedArena;
-use rustc_ast as ast;
-use rustc_ast::expand::allocator::AllocatorKind;
-use rustc_attr as attr;
-use rustc_data_structures::fx::{FxHashMap, FxIndexMap, FxIndexSet};
-use rustc_data_structures::steal::Steal;
-use rustc_data_structures::svh::Svh;
-use rustc_data_structures::sync::Lrc;
-use rustc_data_structures::sync::WorkerLocal;
-use rustc_data_structures::unord::UnordSet;
-use rustc_errors::ErrorGuaranteed;
-use rustc_hir as hir;
-use rustc_hir::def::{DefKind, DocLinkResMap};
-use rustc_hir::def_id::{
- CrateNum, DefId, DefIdMap, DefIdSet, LocalDefId, LocalDefIdMap, LocalDefIdSet,
+use crate::dep_graph::DepKind;
+use crate::query::on_disk_cache::CacheEncoder;
+use crate::query::on_disk_cache::EncodedDepNodeIndex;
+use crate::query::on_disk_cache::OnDiskCache;
+use crate::query::{
+ DynamicQueries, ExternProviders, Providers, QueryArenas, QueryCaches, QueryEngine, QueryStates,
};
+use crate::ty::TyCtxt;
+use field_offset::FieldOffset;
+use measureme::StringId;
+use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::sync::AtomicU64;
+use rustc_hir::def::DefKind;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::hir_id::OwnerId;
-use rustc_hir::lang_items::{LangItem, LanguageItems};
-use rustc_hir::{Crate, ItemLocalId, TraitCandidate};
-use rustc_index::vec::IndexVec;
+use rustc_query_system::dep_graph::DepNodeIndex;
+use rustc_query_system::dep_graph::SerializedDepNodeIndex;
pub(crate) use rustc_query_system::query::QueryJobId;
use rustc_query_system::query::*;
-use rustc_session::config::{EntryFnType, OptLevel, OutputFilenames, SymbolManglingVersion};
-use rustc_session::cstore::{CrateDepKind, CrateSource};
-use rustc_session::cstore::{ExternCrate, ForeignModule, LinkagePreference, NativeLib};
-use rustc_session::lint::LintExpectationId;
-use rustc_session::Limits;
-use rustc_span::symbol::Symbol;
+use rustc_query_system::HandleCycleError;
use rustc_span::{Span, DUMMY_SP};
-use rustc_target::abi;
-use rustc_target::spec::PanicStrategy;
-
-use std::marker::PhantomData;
-use std::mem;
use std::ops::Deref;
-use std::path::PathBuf;
-use std::sync::Arc;
-#[derive(Default)]
+pub struct QueryKeyStringCache {
+ pub def_id_cache: FxHashMap<DefId, StringId>,
+}
+
+impl QueryKeyStringCache {
+ pub fn new() -> QueryKeyStringCache {
+ QueryKeyStringCache { def_id_cache: Default::default() }
+ }
+}
+
+pub struct DynamicQuery<'tcx, C: QueryCache> {
+ pub name: &'static str,
+ pub eval_always: bool,
+ pub dep_kind: DepKind,
+ pub handle_cycle_error: HandleCycleError,
+ pub query_state: FieldOffset<QueryStates<'tcx>, QueryState<C::Key, DepKind>>,
+ pub query_cache: FieldOffset<QueryCaches<'tcx>, C>,
+ pub cache_on_disk: fn(tcx: TyCtxt<'tcx>, key: &C::Key) -> bool,
+ pub execute_query: fn(tcx: TyCtxt<'tcx>, k: C::Key) -> C::Value,
+ pub compute: fn(tcx: TyCtxt<'tcx>, key: C::Key) -> C::Value,
+ pub can_load_from_disk: bool,
+ pub try_load_from_disk: fn(
+ tcx: TyCtxt<'tcx>,
+ key: &C::Key,
+ prev_index: SerializedDepNodeIndex,
+ index: DepNodeIndex,
+ ) -> Option<C::Value>,
+ pub loadable_from_disk:
+ fn(tcx: TyCtxt<'tcx>, key: &C::Key, index: SerializedDepNodeIndex) -> bool,
+ pub hash_result: HashResult<C::Value>,
+ pub value_from_cycle_error: fn(tcx: TyCtxt<'tcx>, cycle: &[QueryInfo<DepKind>]) -> C::Value,
+ pub format_value: fn(&C::Value) -> String,
+}
+
+pub struct QuerySystemFns<'tcx> {
+ pub engine: QueryEngine,
+ pub local_providers: Providers,
+ pub extern_providers: ExternProviders,
+ pub encode_query_results: fn(
+ tcx: TyCtxt<'tcx>,
+ encoder: &mut CacheEncoder<'_, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex,
+ ),
+ pub try_mark_green: fn(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool,
+}
+
pub struct QuerySystem<'tcx> {
+ pub states: QueryStates<'tcx>,
pub arenas: QueryArenas<'tcx>,
pub caches: QueryCaches<'tcx>,
- // Since we erase query value types we tell the typesystem about them with `PhantomData`.
- _phantom_values: QueryPhantomValues<'tcx>,
+ pub dynamic_queries: DynamicQueries<'tcx>,
+
+ /// This provides access to the incremental compilation on-disk cache for query results.
+ /// Do not access this directly. It is only meant to be used by
+ /// `DepGraph::try_mark_green()` and the query infrastructure.
+ /// This is `None` if we are not incremental compilation mode
+ pub on_disk_cache: Option<OnDiskCache<'tcx>>,
+
+ pub fns: QuerySystemFns<'tcx>,
+
+ pub jobs: AtomicU64,
}
#[derive(Copy, Clone)]
@@ -133,7 +134,41 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn try_mark_green(self, dep_node: &dep_graph::DepNode) -> bool {
- self.queries.try_mark_green(self, dep_node)
+ (self.query_system.fns.try_mark_green)(self, dep_node)
+ }
+}
+
+#[inline]
+pub fn query_get_at<'tcx, Cache>(
+ tcx: TyCtxt<'tcx>,
+ execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
+ query_cache: &Cache,
+ span: Span,
+ key: Cache::Key,
+) -> Cache::Value
+where
+ Cache: QueryCache,
+{
+ let key = key.into_query_param();
+ match try_get_cached(tcx, query_cache, &key) {
+ Some(value) => value,
+ None => execute_query(tcx, span, key, QueryMode::Get).unwrap(),
+ }
+}
+
+#[inline]
+pub fn query_ensure<'tcx, Cache>(
+ tcx: TyCtxt<'tcx>,
+ execute_query: fn(TyCtxt<'tcx>, Span, Cache::Key, QueryMode) -> Option<Cache::Value>,
+ query_cache: &Cache,
+ key: Cache::Key,
+ check_cache: bool,
+) where
+ Cache: QueryCache,
+{
+ let key = key.into_query_param();
+ if try_get_cached(tcx, query_cache, &key).is_none() {
+ execute_query(tcx, DUMMY_SP, key, QueryMode::Ensure { check_cache });
}
}
@@ -176,8 +211,8 @@ macro_rules! separate_provide_extern_decl {
([(separate_provide_extern) $($rest:tt)*][$name:ident]) => {
for<'tcx> fn(
TyCtxt<'tcx>,
- query_keys::$name<'tcx>,
- ) -> query_provided::$name<'tcx>
+ queries::$name::Key<'tcx>,
+ ) -> queries::$name::ProvidedValue<'tcx>
};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
separate_provide_extern_decl!([$($modifiers)*][$($args)*])
@@ -202,75 +237,42 @@ macro_rules! separate_provide_extern_default {
};
}
-macro_rules! opt_remap_env_constness {
- ([][$name:ident]) => {};
- ([(remap_env_constness) $($rest:tt)*][$name:ident]) => {
- let $name = $name.without_const();
- };
- ([$other:tt $($modifiers:tt)*][$name:ident]) => {
- opt_remap_env_constness!([$($modifiers)*][$name])
- };
-}
-
macro_rules! define_callbacks {
(
$($(#[$attr:meta])*
[$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
- // HACK(eddyb) this is like the `impl QueryConfig for queries::$name`
- // below, but using type aliases instead of associated types, to bypass
- // the limitations around normalizing under HRTB - for example, this:
- // `for<'tcx> fn(...) -> <queries::$name<'tcx> as QueryConfig<TyCtxt<'tcx>>>::Value`
- // doesn't currently normalize to `for<'tcx> fn(...) -> query_values::$name<'tcx>`.
- // This is primarily used by the `provide!` macro in `rustc_metadata`.
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_keys {
- use super::*;
-
- $(pub type $name<'tcx> = $($K)*;)*
- }
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_keys_local {
- use super::*;
-
- $(pub type $name<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);)*
- }
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_values {
- use super::*;
-
- $(pub type $name<'tcx> = $V;)*
- }
-
- /// This module specifies the type returned from query providers and the type used for
- /// decoding. For regular queries this is the declared returned type `V`, but
- /// `arena_cache` will use `<V as Deref>::Target` instead.
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_provided {
- use super::*;
-
- $(
- pub type $name<'tcx> = query_if_arena!([$($modifiers)*] (<$V as Deref>::Target) ($V));
- )*
- }
-
- /// This module has a function per query which takes a `query_provided` value and coverts
- /// it to a regular `V` value by allocating it on an arena if the query has the
- /// `arena_cache` modifier. This will happen when computing the query using a provider or
- /// decoding a stored result.
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_provided_to_value {
- use super::*;
-
- $(
+ #[allow(unused_lifetimes)]
+ pub mod queries {
+ $(pub mod $name {
+ use super::super::*;
+
+ pub type Key<'tcx> = $($K)*;
+ pub type Value<'tcx> = $V;
+
+ pub type LocalKey<'tcx> = local_key_if_separate_extern!([$($modifiers)*] $($K)*);
+
+ /// This type alias specifies the type returned from query providers and the type
+ /// used for decoding. For regular queries this is the declared returned type `V`,
+ /// but `arena_cache` will use `<V as Deref>::Target` instead.
+ pub type ProvidedValue<'tcx> = query_if_arena!(
+ [$($modifiers)*]
+ (<$V as Deref>::Target)
+ ($V)
+ );
+
+ /// This function takes `ProvidedValue` and coverts it to an erased `Value` by
+ /// allocating it on an arena if the query has the `arena_cache` modifier. The
+ /// value is then erased and returned. This will happen when computing the query
+ /// using a provider or decoding a stored result.
#[inline(always)]
- pub fn $name<'tcx>(
+ pub fn provided_to_erased<'tcx>(
_tcx: TyCtxt<'tcx>,
- value: query_provided::$name<'tcx>,
- ) -> Erase<query_values::$name<'tcx>> {
+ value: ProvidedValue<'tcx>,
+ ) -> Erase<Value<'tcx>> {
erase(query_if_arena!([$($modifiers)*]
{
- if mem::needs_drop::<query_provided::$name<'tcx>>() {
+ if mem::needs_drop::<ProvidedValue<'tcx>>() {
&*_tcx.query_system.arenas.$name.alloc(value)
} else {
&*_tcx.arena.dropless.alloc(value)
@@ -279,46 +281,40 @@ macro_rules! define_callbacks {
(value)
))
}
- )*
- }
- #[allow(nonstandard_style, unused_lifetimes)]
- pub mod query_storage {
- use super::*;
- $(
- pub type $name<'tcx> = <<$($K)* as Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>>::Cache;
- )*
- }
+ pub type Storage<'tcx> = <
+ <$($K)* as keys::Key>::CacheSelector as CacheSelector<'tcx, Erase<$V>>
+ >::Cache;
- $(
- // Ensure that keys grow no larger than 64 bytes
- #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
- const _: () = {
- if mem::size_of::<query_keys::$name<'static>>() > 64 {
- panic!("{}", concat!(
- "the query `",
- stringify!($name),
- "` has a key type `",
- stringify!($($K)*),
- "` that is too large"
- ));
- }
- };
-
- // Ensure that values grow no larger than 64 bytes
- #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
- const _: () = {
- if mem::size_of::<query_values::$name<'static>>() > 64 {
- panic!("{}", concat!(
- "the query `",
- stringify!($name),
- "` has a value type `",
- stringify!($V),
- "` that is too large"
- ));
- }
- };
- )*
+ // Ensure that keys grow no larger than 64 bytes
+ #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+ const _: () = {
+ if mem::size_of::<Key<'static>>() > 64 {
+ panic!("{}", concat!(
+ "the query `",
+ stringify!($name),
+ "` has a key type `",
+ stringify!($($K)*),
+ "` that is too large"
+ ));
+ }
+ };
+
+ // Ensure that values grow no larger than 64 bytes
+ #[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
+ const _: () = {
+ if mem::size_of::<Value<'static>>() > 64 {
+ panic!("{}", concat!(
+ "the query `",
+ stringify!($name),
+ "` has a value type `",
+ stringify!($V),
+ "` that is too large"
+ ));
+ }
+ };
+ })*
+ }
pub struct QueryArenas<'tcx> {
$($(#[$attr])* pub $name: query_if_arena!([$($modifiers)*]
@@ -339,31 +335,21 @@ macro_rules! define_callbacks {
}
#[derive(Default)]
- pub struct QueryPhantomValues<'tcx> {
- $($(#[$attr])* pub $name: PhantomData<query_values::$name<'tcx>>,)*
- }
-
- #[derive(Default)]
pub struct QueryCaches<'tcx> {
- $($(#[$attr])* pub $name: query_storage::$name<'tcx>,)*
+ $($(#[$attr])* pub $name: queries::$name::Storage<'tcx>,)*
}
impl<'tcx> TyCtxtEnsure<'tcx> {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
- let key = key.into_query_param();
- opt_remap_env_constness!([$($modifiers)*][key]);
-
- match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) {
- Some(_) => return,
- None => self.tcx.queries.$name(
- self.tcx,
- DUMMY_SP,
- key,
- QueryMode::Ensure { check_cache: false },
- ),
- };
+ query_ensure(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ key.into_query_param(),
+ false,
+ );
})*
}
@@ -371,18 +357,13 @@ macro_rules! define_callbacks {
$($(#[$attr])*
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) {
- let key = key.into_query_param();
- opt_remap_env_constness!([$($modifiers)*][key]);
-
- match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) {
- Some(_) => return,
- None => self.tcx.queries.$name(
- self.tcx,
- DUMMY_SP,
- key,
- QueryMode::Ensure { check_cache: true },
- ),
- };
+ query_ensure(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ key.into_query_param(),
+ true,
+ );
})*
}
@@ -401,21 +382,34 @@ macro_rules! define_callbacks {
#[inline(always)]
pub fn $name(self, key: query_helper_param_ty!($($K)*)) -> $V
{
- let key = key.into_query_param();
- opt_remap_env_constness!([$($modifiers)*][key]);
-
- restore::<$V>(match try_get_cached(self.tcx, &self.tcx.query_system.caches.$name, &key) {
- Some(value) => value,
- None => self.tcx.queries.$name(self.tcx, self.span, key, QueryMode::Get).unwrap(),
- })
+ restore::<$V>(query_get_at(
+ self.tcx,
+ self.tcx.query_system.fns.engine.$name,
+ &self.tcx.query_system.caches.$name,
+ self.span,
+ key.into_query_param(),
+ ))
})*
}
+ pub struct DynamicQueries<'tcx> {
+ $(
+ pub $name: DynamicQuery<'tcx, queries::$name::Storage<'tcx>>,
+ )*
+ }
+
+ #[derive(Default)]
+ pub struct QueryStates<'tcx> {
+ $(
+ pub $name: QueryState<$($K)*, DepKind>,
+ )*
+ }
+
pub struct Providers {
$(pub $name: for<'tcx> fn(
TyCtxt<'tcx>,
- query_keys_local::$name<'tcx>,
- ) -> query_provided::$name<'tcx>,)*
+ queries::$name::LocalKey<'tcx>,
+ ) -> queries::$name::ProvidedValue<'tcx>,)*
}
pub struct ExternProviders {
@@ -456,19 +450,13 @@ macro_rules! define_callbacks {
fn clone(&self) -> Self { *self }
}
- pub trait QueryEngine<'tcx>: rustc_data_structures::sync::Sync {
- fn as_any(&'tcx self) -> &'tcx dyn std::any::Any;
-
- fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool;
-
- $($(#[$attr])*
- fn $name(
- &'tcx self,
- tcx: TyCtxt<'tcx>,
- span: Span,
- key: query_keys::$name<'tcx>,
- mode: QueryMode,
- ) -> Option<Erase<$V>>;)*
+ pub struct QueryEngine {
+ $(pub $name: for<'tcx> fn(
+ TyCtxt<'tcx>,
+ Span,
+ queries::$name::Key<'tcx>,
+ QueryMode,
+ ) -> Option<Erase<$V>>,)*
}
};
}
@@ -490,22 +478,41 @@ macro_rules! define_feedable {
$(impl<'tcx, K: IntoQueryParam<$($K)*> + Copy> TyCtxtFeed<'tcx, K> {
$(#[$attr])*
#[inline(always)]
- pub fn $name(self, value: query_provided::$name<'tcx>) -> $V {
+ pub fn $name(self, value: queries::$name::ProvidedValue<'tcx>) {
let key = self.key().into_query_param();
- opt_remap_env_constness!([$($modifiers)*][key]);
let tcx = self.tcx;
- let erased = query_provided_to_value::$name(tcx, value);
+ let erased = queries::$name::provided_to_erased(tcx, value);
let value = restore::<$V>(erased);
let cache = &tcx.query_system.caches.$name;
+ let hasher: Option<fn(&mut StableHashingContext<'_>, &_) -> _> = hash_result!([$($modifiers)*]);
match try_get_cached(tcx, cache, &key) {
Some(old) => {
let old = restore::<$V>(old);
- bug!(
- "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
- stringify!($name),
- )
+ if let Some(hasher) = hasher {
+ let (value_hash, old_hash): (Fingerprint, Fingerprint) = tcx.with_stable_hashing_context(|mut hcx|
+ (hasher(&mut hcx, &value), hasher(&mut hcx, &old))
+ );
+ if old_hash != value_hash {
+ // We have an inconsistency. This can happen if one of the two
+ // results is tainted by errors. In this case, delay a bug to
+ // ensure compilation is doomed, and keep the `old` value.
+ tcx.sess.delay_span_bug(DUMMY_SP, format!(
+ "Trying to feed an already recorded value for query {} key={key:?}:\n\
+ old value: {old:?}\nnew value: {value:?}",
+ stringify!($name),
+ ));
+ }
+ } else {
+ // The query is `no_hash`, so we have no way to perform a sanity check.
+ // If feeding the same value multiple times needs to be supported,
+ // the query should not be marked `no_hash`.
+ bug!(
+ "Trying to feed an already recorded value for query {} key={key:?}:\nold value: {old:?}\nnew value: {value:?}",
+ stringify!($name),
+ )
+ }
}
None => {
let dep_node = dep_graph::DepNode::construct(tcx, dep_graph::DepKind::$name, &key);
@@ -517,7 +524,6 @@ macro_rules! define_feedable {
hash_result!([$($modifiers)*]),
);
cache.complete(key, erased, dep_node_index);
- value
}
}
}
@@ -537,9 +543,6 @@ macro_rules! define_feedable {
// Queries marked with `fatal_cycle` do not need the latter implementation,
// as they will raise an fatal error on query cycles instead.
-rustc_query_append! { define_callbacks! }
-rustc_feedable_queries! { define_feedable! }
-
mod sealed {
use super::{DefId, LocalDefId, OwnerId};
@@ -587,7 +590,7 @@ mod sealed {
}
}
-use sealed::IntoQueryParam;
+pub use sealed::IntoQueryParam;
impl<'tcx> TyCtxt<'tcx> {
pub fn def_kind(self, def_id: impl IntoQueryParam<DefId>) -> DefKind {
diff --git a/compiler/rustc_middle/src/thir.rs b/compiler/rustc_middle/src/thir.rs
index 7d79a13d3..813e109c4 100644
--- a/compiler/rustc_middle/src/thir.rs
+++ b/compiler/rustc_middle/src/thir.rs
@@ -14,13 +14,13 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::RangeEnd;
use rustc_index::newtype_index;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::middle::region;
use rustc_middle::mir::interpret::AllocId;
use rustc_middle::mir::{self, BinOp, BorrowKind, FakeReadCause, Mutability, UnOp};
use rustc_middle::ty::adjustment::PointerCast;
use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, AdtDef, FnSig, Ty, UpvarSubsts};
+use rustc_middle::ty::{self, AdtDef, FnSig, List, Ty, UpvarSubsts};
use rustc_middle::ty::{CanonicalUserType, CanonicalUserTypeAnnotation};
use rustc_span::def_id::LocalDefId;
use rustc_span::{sym, Span, Symbol, DUMMY_SP};
@@ -234,7 +234,6 @@ pub enum StmtKind<'tcx> {
}
#[derive(Clone, Debug, Copy, PartialEq, Eq, Hash, HashStable, TyEncodable, TyDecodable)]
-#[derive(TypeFoldable, TypeVisitable)]
pub struct LocalVarId(pub hir::HirId);
/// A THIR expression.
@@ -481,6 +480,11 @@ pub enum ExprKind<'tcx> {
},
/// Inline assembly, i.e. `asm!()`.
InlineAsm(Box<InlineAsmExpr<'tcx>>),
+ /// Field offset (`offset_of!`)
+ OffsetOf {
+ container: Ty<'tcx>,
+ fields: &'tcx List<FieldIdx>,
+ },
/// An expression taking a reference to a thread local.
ThreadLocalRef(DefId),
/// A `yield` expression.
@@ -929,8 +933,8 @@ mod size_asserts {
static_assert_size!(Block, 56);
static_assert_size!(Expr<'_>, 64);
static_assert_size!(ExprKind<'_>, 40);
- static_assert_size!(Pat<'_>, 72);
- static_assert_size!(PatKind<'_>, 56);
+ static_assert_size!(Pat<'_>, 64);
+ static_assert_size!(PatKind<'_>, 48);
static_assert_size!(Stmt<'_>, 56);
static_assert_size!(StmtKind<'_>, 48);
// tidy-alphabetical-end
diff --git a/compiler/rustc_middle/src/thir/visit.rs b/compiler/rustc_middle/src/thir/visit.rs
index 5614528c4..5c7ec31cf 100644
--- a/compiler/rustc_middle/src/thir/visit.rs
+++ b/compiler/rustc_middle/src/thir/visit.rs
@@ -160,6 +160,7 @@ pub fn walk_expr<'a, 'tcx: 'a, V: Visitor<'a, 'tcx>>(visitor: &mut V, expr: &Exp
}
}
}
+ OffsetOf { container: _, fields: _ } => {}
ThreadLocalRef(_) => {}
Yield { value } => visitor.visit_expr(&visitor.thir()[value]),
}
diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs
index 91f07389f..0a903a769 100644
--- a/compiler/rustc_middle/src/traits/mod.rs
+++ b/compiler/rustc_middle/src/traits/mod.rs
@@ -199,7 +199,7 @@ impl<'tcx> ObligationCause<'tcx> {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct UnifyReceiverContext<'tcx> {
pub assoc_item: ty::AssocItem,
@@ -207,7 +207,7 @@ pub struct UnifyReceiverContext<'tcx> {
pub substs: SubstsRef<'tcx>,
}
-#[derive(Clone, PartialEq, Eq, Hash, Lift, Default, HashStable)]
+#[derive(Clone, PartialEq, Eq, Lift, Default, HashStable)]
#[derive(TypeVisitable, TypeFoldable, TyEncodable, TyDecodable)]
pub struct InternedObligationCauseCode<'tcx> {
/// `None` for `ObligationCauseCode::MiscObligation` (a common case, occurs ~60% of
@@ -243,7 +243,7 @@ impl<'tcx> std::ops::Deref for InternedObligationCauseCode<'tcx> {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub enum ObligationCauseCode<'tcx> {
/// Not well classified or should be obvious from the span.
@@ -281,9 +281,6 @@ pub enum ObligationCauseCode<'tcx> {
/// A type like `Box<Foo<'a> + 'b>` is WF only if `'b: 'a`.
ObjectTypeBound(Ty<'tcx>, ty::Region<'tcx>),
- /// Obligation incurred due to an object cast.
- ObjectCastObligation(/* Concrete type */ Ty<'tcx>, /* Object type */ Ty<'tcx>),
-
/// Obligation incurred due to a coercion.
Coercion {
source: Ty<'tcx>,
@@ -444,6 +441,10 @@ pub enum ObligationCauseCode<'tcx> {
AscribeUserTypeProvePredicate(Span),
RustCall,
+
+ /// Obligations to prove that a `std::ops::Drop` impl is not stronger than
+ /// the ADT it's being implemented for.
+ DropImpl,
}
/// The 'location' at which we try to perform HIR-based wf checking.
@@ -468,7 +469,7 @@ pub enum WellFormedLoc {
},
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct ImplDerivedObligationCause<'tcx> {
pub derived: DerivedObligationCause<'tcx>,
@@ -529,7 +530,7 @@ impl<'tcx> ty::Lift<'tcx> for StatementAsExpression {
}
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct MatchExpressionArmCause<'tcx> {
pub arm_block_id: Option<hir::HirId>,
@@ -545,7 +546,7 @@ pub struct MatchExpressionArmCause<'tcx> {
pub opt_suggest_box_span: Option<Span>,
}
-#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
#[derive(Lift, TypeFoldable, TypeVisitable, HashStable, TyEncodable, TyDecodable)]
pub struct IfExpressionCause<'tcx> {
pub then_id: hir::HirId,
@@ -556,7 +557,7 @@ pub struct IfExpressionCause<'tcx> {
pub opt_suggest_box_span: Option<Span>,
}
-#[derive(Clone, Debug, PartialEq, Eq, Hash, Lift, HashStable, TyEncodable, TyDecodable)]
+#[derive(Clone, Debug, PartialEq, Eq, Lift, HashStable, TyEncodable, TyDecodable)]
#[derive(TypeVisitable, TypeFoldable)]
pub struct DerivedObligationCause<'tcx> {
/// The trait predicate of the parent obligation that led to the
@@ -569,18 +570,14 @@ pub struct DerivedObligationCause<'tcx> {
pub parent_code: InternedObligationCauseCode<'tcx>,
}
-#[derive(Clone, Debug, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Clone, Debug, TypeVisitable, Lift)]
pub enum SelectionError<'tcx> {
/// The trait is not implemented.
Unimplemented,
/// After a closure impl has selected, its "outputs" were evaluated
/// (which for closures includes the "input" type params) and they
/// didn't resolve. See `confirm_poly_trait_refs` for more.
- OutputTypeParameterMismatch(
- ty::PolyTraitRef<'tcx>,
- ty::PolyTraitRef<'tcx>,
- ty::error::TypeError<'tcx>,
- ),
+ OutputTypeParameterMismatch(Box<SelectionOutputTypeParameterMismatch<'tcx>>),
/// The trait pointed by `DefId` is not object safe.
TraitNotObjectSafe(DefId),
/// A given constant couldn't be evaluated.
@@ -592,6 +589,13 @@ pub enum SelectionError<'tcx> {
ErrorReporting,
}
+#[derive(Clone, Debug, TypeVisitable, Lift)]
+pub struct SelectionOutputTypeParameterMismatch<'tcx> {
+ pub found_trait_ref: ty::PolyTraitRef<'tcx>,
+ pub expected_trait_ref: ty::PolyTraitRef<'tcx>,
+ pub terr: ty::error::TypeError<'tcx>,
+}
+
/// When performing resolution, it is typically the case that there
/// can be one of three outcomes:
///
@@ -1027,10 +1031,7 @@ impl ObjectSafetyViolation {
) => {
err.span_suggestion(
*span,
- &format!(
- "consider changing method `{}`'s `self` parameter to be `&self`",
- name
- ),
+ format!("consider changing method `{}`'s `self` parameter to be `&self`", name),
"&Self",
Applicability::MachineApplicable,
);
@@ -1038,7 +1039,7 @@ impl ObjectSafetyViolation {
ObjectSafetyViolation::AssocConst(name, _)
| ObjectSafetyViolation::GAT(name, _)
| ObjectSafetyViolation::Method(name, ..) => {
- err.help(&format!("consider moving `{}` to another trait", name));
+ err.help(format!("consider moving `{}` to another trait", name));
}
}
}
@@ -1107,3 +1108,14 @@ pub enum CodegenObligationError {
Unimplemented,
FulfillmentError,
}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
+pub enum DefiningAnchor {
+ /// `DefId` of the item.
+ Bind(LocalDefId),
+ /// When opaque types are not resolved, we `Bubble` up, meaning
+ /// return the opaque/hidden type pair from query, for caller of query to handle it.
+ Bubble,
+ /// Used to catch type mismatch errors when handling opaque types.
+ Error,
+}
diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs
index c4f871875..eae5a280e 100644
--- a/compiler/rustc_middle/src/traits/query.rs
+++ b/compiler/rustc_middle/src/traits/query.rs
@@ -95,8 +95,6 @@ pub type CanonicalTypeOpNormalizeGoal<'tcx, T> =
#[derive(Copy, Clone, Debug, HashStable, PartialEq, Eq)]
pub struct NoSolution;
-pub type Fallible<T> = Result<T, NoSolution>;
-
impl<'tcx> From<TypeError<'tcx>> for NoSolution {
fn from(_: TypeError<'tcx>) -> NoSolution {
NoSolution
diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs
index 1cc9fd526..f2dda003b 100644
--- a/compiler/rustc_middle/src/traits/select.rs
+++ b/compiler/rustc_middle/src/traits/select.rs
@@ -103,7 +103,7 @@ pub type EvaluationCache<'tcx> = Cache<
/// required for associated types to work in default impls, as the bounds
/// are visible both as projection bounds and as where-clauses from the
/// parameter environment.
-#[derive(PartialEq, Eq, Debug, Clone, TypeFoldable, TypeVisitable)]
+#[derive(PartialEq, Eq, Debug, Clone, TypeVisitable)]
pub enum SelectionCandidate<'tcx> {
/// A builtin implementation for some specific traits, used in cases
/// where we cannot rely an ordinary library implementations.
diff --git a/compiler/rustc_middle/src/traits/solve.rs b/compiler/rustc_middle/src/traits/solve.rs
index fef2be133..2c5b64a59 100644
--- a/compiler/rustc_middle/src/traits/solve.rs
+++ b/compiler/rustc_middle/src/traits/solve.rs
@@ -5,13 +5,13 @@ use rustc_query_system::cache::Cache;
use crate::infer::canonical::{CanonicalVarValues, QueryRegionConstraints};
use crate::traits::query::NoSolution;
-use crate::traits::Canonical;
+use crate::traits::{Canonical, DefiningAnchor};
use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeVisitable,
TypeVisitor,
};
-pub type EvaluationCache<'tcx> = Cache<CanonicalGoal<'tcx>, QueryResult<'tcx>>;
+pub type EvaluationCache<'tcx> = Cache<CanonicalInput<'tcx>, QueryResult<'tcx>>;
/// A goal is a statement, i.e. `predicate`, we want to prove
/// given some assumptions, i.e. `param_env`.
@@ -96,7 +96,31 @@ pub enum MaybeCause {
Overflow,
}
-pub type CanonicalGoal<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, Goal<'tcx, T>>;
+#[derive(Debug, PartialEq, Eq, Clone, Copy, Hash, TypeFoldable, TypeVisitable)]
+pub struct QueryInput<'tcx, T> {
+ pub goal: Goal<'tcx, T>,
+ pub anchor: DefiningAnchor,
+ pub predefined_opaques_in_body: PredefinedOpaques<'tcx>,
+}
+
+/// Additional constraints returned on success.
+#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
+pub struct PredefinedOpaquesData<'tcx> {
+ pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
+}
+
+#[derive(Debug, PartialEq, Eq, Copy, Clone, Hash)]
+pub struct PredefinedOpaques<'tcx>(pub(crate) Interned<'tcx, PredefinedOpaquesData<'tcx>>);
+
+impl<'tcx> std::ops::Deref for PredefinedOpaques<'tcx> {
+ type Target = PredefinedOpaquesData<'tcx>;
+
+ fn deref(&self) -> &Self::Target {
+ &self.0
+ }
+}
+
+pub type CanonicalInput<'tcx, T = ty::Predicate<'tcx>> = Canonical<'tcx, QueryInput<'tcx, T>>;
pub type CanonicalResponse<'tcx> = Canonical<'tcx, Response<'tcx>>;
@@ -120,11 +144,11 @@ impl<'tcx> std::ops::Deref for ExternalConstraints<'tcx> {
}
/// Additional constraints returned on success.
-#[derive(Debug, PartialEq, Eq, Clone, Hash, Default, TypeFoldable, TypeVisitable)]
+#[derive(Debug, PartialEq, Eq, Clone, Hash, Default)]
pub struct ExternalConstraintsData<'tcx> {
// FIXME: implement this.
pub region_constraints: QueryRegionConstraints<'tcx>,
- pub opaque_types: Vec<(Ty<'tcx>, Ty<'tcx>)>,
+ pub opaque_types: Vec<(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)>,
}
// FIXME: Having to clone `region_constraints` for folding feels bad and
@@ -165,3 +189,40 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ExternalConstraints<'tcx> {
ControlFlow::Continue(())
}
}
+
+// FIXME: Having to clone `region_constraints` for folding feels bad and
+// probably isn't great wrt performance.
+//
+// Not sure how to fix this, maybe we should also intern `opaque_types` and
+// `region_constraints` here or something.
+impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
+ fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
+ self,
+ folder: &mut F,
+ ) -> Result<Self, F::Error> {
+ Ok(FallibleTypeFolder::interner(folder).mk_predefined_opaques_in_body(
+ PredefinedOpaquesData {
+ opaque_types: self
+ .opaque_types
+ .iter()
+ .map(|opaque| opaque.try_fold_with(folder))
+ .collect::<Result<_, F::Error>>()?,
+ },
+ ))
+ }
+
+ fn fold_with<F: TypeFolder<TyCtxt<'tcx>>>(self, folder: &mut F) -> Self {
+ TypeFolder::interner(folder).mk_predefined_opaques_in_body(PredefinedOpaquesData {
+ opaque_types: self.opaque_types.iter().map(|opaque| opaque.fold_with(folder)).collect(),
+ })
+ }
+}
+
+impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for PredefinedOpaques<'tcx> {
+ fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
+ &self,
+ visitor: &mut V,
+ ) -> std::ops::ControlFlow<V::BreakTy> {
+ self.opaque_types.visit_with(visitor)
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs
index 468c2c818..cbc68fde9 100644
--- a/compiler/rustc_middle/src/ty/_match.rs
+++ b/compiler/rustc_middle/src/ty/_match.rs
@@ -83,7 +83,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(self.tcx().ty_error(guar)),
- _ => relate::super_relate_tys(self, a, b),
+ _ => relate::structurally_relate_tys(self, a, b),
}
}
@@ -109,7 +109,7 @@ impl<'tcx> TypeRelation<'tcx> for Match<'tcx> {
_ => {}
}
- relate::super_relate_consts(self, a, b)
+ relate::structurally_relate_consts(self, a, b)
}
fn binders<T>(
diff --git a/compiler/rustc_middle/src/ty/abstract_const.rs b/compiler/rustc_middle/src/ty/abstract_const.rs
index f889ce827..a39631da9 100644
--- a/compiler/rustc_middle/src/ty/abstract_const.rs
+++ b/compiler/rustc_middle/src/ty/abstract_const.rs
@@ -1,10 +1,9 @@
-//! A subset of a mir body used for const evaluatability checking.
+//! A subset of a mir body used for const evaluability checking.
use crate::ty::{
self, Const, EarlyBinder, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
TypeVisitableExt,
};
use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def_id::DefId;
#[derive(Hash, Debug, Clone, Copy, Ord, PartialOrd, PartialEq, Eq)]
#[derive(TyDecodable, TyEncodable, HashStable, TypeVisitable, TypeFoldable)]
@@ -35,19 +34,6 @@ TrivialTypeTraversalAndLiftImpls! {
pub type BoundAbstractConst<'tcx> = Result<Option<EarlyBinder<ty::Const<'tcx>>>, ErrorGuaranteed>;
impl<'tcx> TyCtxt<'tcx> {
- /// Returns a const without substs applied
- pub fn bound_abstract_const(
- self,
- uv: ty::WithOptConstParam<DefId>,
- ) -> BoundAbstractConst<'tcx> {
- let ac = if let Some((did, param_did)) = uv.as_const_arg() {
- self.thir_abstract_const_of_const_arg((did, param_did))
- } else {
- self.thir_abstract_const(uv.did)
- };
- Ok(ac?.map(|ac| EarlyBinder(ac)))
- }
-
pub fn expand_abstract_consts<T: TypeFoldable<TyCtxt<'tcx>>>(self, ac: T) -> T {
struct Expander<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -66,11 +52,12 @@ impl<'tcx> TyCtxt<'tcx> {
}
fn fold_const(&mut self, c: Const<'tcx>) -> Const<'tcx> {
let ct = match c.kind() {
- ty::ConstKind::Unevaluated(uv) => match self.tcx.bound_abstract_const(uv.def) {
- Err(e) => self.tcx.const_error_with_guaranteed(c.ty(), e),
+ ty::ConstKind::Unevaluated(uv) => match self.tcx.thir_abstract_const(uv.def) {
+ Err(e) => self.tcx.const_error(c.ty(), e),
Ok(Some(bac)) => {
let substs = self.tcx.erase_regions(uv.substs);
- bac.subst(self.tcx, substs)
+ let bac = bac.subst(self.tcx, substs);
+ return bac.fold_with(self);
}
Ok(None) => c,
},
diff --git a/compiler/rustc_middle/src/ty/adt.rs b/compiler/rustc_middle/src/ty/adt.rs
index 3a03c0901..7c5c030c2 100644
--- a/compiler/rustc_middle/src/ty/adt.rs
+++ b/compiler/rustc_middle/src/ty/adt.rs
@@ -10,7 +10,7 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, DefKind, Res};
use rustc_hir::def_id::DefId;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_query_system::ich::StableHashingContext;
use rustc_session::DataTypeKind;
use rustc_span::symbol::sym;
@@ -26,7 +26,7 @@ use super::{Destructor, FieldDef, GenericPredicates, Ty, TyCtxt, VariantDef, Var
bitflags! {
#[derive(HashStable, TyEncodable, TyDecodable)]
- pub struct AdtFlags: u32 {
+ pub struct AdtFlags: u16 {
const NO_ADT_FLAGS = 0;
/// Indicates whether the ADT is an enum.
const IS_ENUM = 1 << 0;
@@ -111,12 +111,30 @@ impl Ord for AdtDefData {
}
}
-/// There should be only one AdtDef for each `did`, therefore
-/// it is fine to implement `PartialEq` only based on `did`.
impl PartialEq for AdtDefData {
#[inline]
fn eq(&self, other: &Self) -> bool {
- self.did == other.did
+ // There should be only one `AdtDefData` for each `def_id`, therefore
+ // it is fine to implement `PartialEq` only based on `def_id`.
+ //
+ // Below, we exhaustively destructure `self` and `other` so that if the
+ // definition of `AdtDefData` changes, a compile-error will be produced,
+ // reminding us to revisit this assumption.
+
+ let Self { did: self_def_id, variants: _, flags: _, repr: _ } = self;
+ let Self { did: other_def_id, variants: _, flags: _, repr: _ } = other;
+
+ let res = self_def_id == other_def_id;
+
+ // Double check that implicit assumption detailed above.
+ if cfg!(debug_assertions) && res {
+ let deep = self.flags == other.flags
+ && self.repr == other.repr
+ && self.variants == other.variants;
+ assert!(deep, "AdtDefData for the same def-id has differing data");
+ }
+
+ res
}
}
@@ -188,7 +206,7 @@ impl<'tcx> AdtDef<'tcx> {
}
}
-#[derive(Copy, Clone, Debug, Eq, PartialEq, Hash, HashStable, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Debug, Eq, PartialEq, HashStable, TyEncodable, TyDecodable)]
pub enum AdtKind {
Struct,
Union,
diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs
index f29bf92b0..be7b2b7ec 100644
--- a/compiler/rustc_middle/src/ty/closure.rs
+++ b/compiler/rustc_middle/src/ty/closure.rs
@@ -5,6 +5,7 @@ use crate::{mir, ty};
use std::fmt::Write;
+use crate::query::Providers;
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{self as hir, LangItem};
@@ -457,6 +458,6 @@ impl BorrowKind {
}
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { closure_typeinfo, ..*providers }
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { closure_typeinfo, ..*providers }
}
diff --git a/compiler/rustc_middle/src/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs
index 8ef4a46a7..7fc75674d 100644
--- a/compiler/rustc_middle/src/ty/codec.rs
+++ b/compiler/rustc_middle/src/ty/codec.rs
@@ -19,6 +19,7 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_middle::ty::TyCtxt;
use rustc_serialize::{Decodable, Encodable};
use rustc_span::Span;
+use rustc_target::abi::FieldIdx;
pub use rustc_type_ir::{TyDecoder, TyEncoder};
use std::hash::Hash;
use std::intrinsics;
@@ -401,6 +402,15 @@ impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<ty
}
}
+impl<'tcx, D: TyDecoder<I = TyCtxt<'tcx>>> RefDecodable<'tcx, D> for ty::List<FieldIdx> {
+ fn decode(decoder: &mut D) -> &'tcx Self {
+ let len = decoder.read_usize();
+ decoder
+ .interner()
+ .mk_fields_from_iter((0..len).map::<FieldIdx, _>(|_| Decodable::decode(decoder)))
+ }
+}
+
impl_decodable_via_ref! {
&'tcx ty::TypeckResults<'tcx>,
&'tcx ty::List<Ty<'tcx>>,
@@ -412,6 +422,7 @@ impl_decodable_via_ref! {
&'tcx mir::coverage::CodeRegion,
&'tcx ty::List<ty::BoundVariableKind>,
&'tcx ty::List<ty::Predicate<'tcx>>,
+ &'tcx ty::List<FieldIdx>,
}
#[macro_export]
@@ -489,36 +500,40 @@ impl_arena_copy_decoder! {<'tcx>
macro_rules! implement_ty_decoder {
($DecoderName:ident <$($typaram:tt),*>) => {
mod __ty_decoder_impl {
- use std::borrow::Cow;
use rustc_serialize::Decoder;
use super::$DecoderName;
impl<$($typaram ),*> Decoder for $DecoderName<$($typaram),*> {
$crate::__impl_decoder_methods! {
+ read_usize -> usize;
read_u128 -> u128;
read_u64 -> u64;
read_u32 -> u32;
read_u16 -> u16;
read_u8 -> u8;
- read_usize -> usize;
+ read_isize -> isize;
read_i128 -> i128;
read_i64 -> i64;
read_i32 -> i32;
read_i16 -> i16;
- read_i8 -> i8;
- read_isize -> isize;
-
- read_bool -> bool;
- read_char -> char;
- read_str -> &str;
}
#[inline]
fn read_raw_bytes(&mut self, len: usize) -> &[u8] {
self.opaque.read_raw_bytes(len)
}
+
+ #[inline]
+ fn peek_byte(&self) -> u8 {
+ self.opaque.peek_byte()
+ }
+
+ #[inline]
+ fn position(&self) -> usize {
+ self.opaque.position()
+ }
}
}
}
diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs
index bcedae233..1a4bd1481 100644
--- a/compiler/rustc_middle/src/ty/consts.rs
+++ b/compiler/rustc_middle/src/ty/consts.rs
@@ -6,7 +6,6 @@ use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::LocalDefId;
use rustc_macros::HashStable;
-use std::fmt;
mod int;
mod kind;
@@ -21,15 +20,6 @@ pub use valtree::*;
#[rustc_pass_by_value]
pub struct Const<'tcx>(pub(super) Interned<'tcx, ConstData<'tcx>>);
-impl<'tcx> fmt::Debug for Const<'tcx> {
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- // This reflects what `Const` looked liked before `Interned` was
- // introduced. We print it like this to avoid having to update expected
- // output in a lot of tests.
- write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
- }
-}
-
/// Typed constant value.
#[derive(PartialEq, Eq, PartialOrd, Ord, Hash, HashStable, TyEncodable, TyDecodable)]
pub struct ConstData<'tcx> {
@@ -53,19 +43,12 @@ impl<'tcx> Const<'tcx> {
/// Literals and const generic parameters are eagerly converted to a constant, everything else
/// becomes `Unevaluated`.
- pub fn from_anon_const(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self {
- Self::from_opt_const_arg_anon_const(tcx, ty::WithOptConstParam::unknown(def_id))
- }
-
#[instrument(skip(tcx), level = "debug")]
- pub fn from_opt_const_arg_anon_const(
- tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
- ) -> Self {
- let body_id = match tcx.hir().get_by_def_id(def.did) {
+ pub fn from_anon_const(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Self {
+ let body_id = match tcx.hir().get_by_def_id(def) {
hir::Node::AnonConst(ac) => ac.body,
_ => span_bug!(
- tcx.def_span(def.did.to_def_id()),
+ tcx.def_span(def.to_def_id()),
"from_anon_const can only process anonymous constants"
),
};
@@ -73,17 +56,14 @@ impl<'tcx> Const<'tcx> {
let expr = &tcx.hir().body(body_id).value;
debug!(?expr);
- let ty = tcx
- .type_of(def.def_id_for_type_of())
- .no_bound_vars()
- .expect("const parameter types cannot be generic");
+ let ty = tcx.type_of(def).no_bound_vars().expect("const parameter types cannot be generic");
match Self::try_eval_lit_or_param(tcx, ty, expr) {
Some(v) => v,
None => tcx.mk_const(
ty::UnevaluatedConst {
- def: def.to_global(),
- substs: InternalSubsts::identity_for_item(tcx, def.did),
+ def: def.to_def_id(),
+ substs: InternalSubsts::identity_for_item(tcx, def.to_def_id()),
},
ty,
),
@@ -124,7 +104,7 @@ impl<'tcx> Const<'tcx> {
Err(e) => {
tcx.sess.delay_span_bug(
expr.span,
- &format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
+ format!("Const::from_anon_const: couldn't lit_to_const {:?}", e),
);
}
}
@@ -152,9 +132,7 @@ impl<'tcx> Const<'tcx> {
ty::ConstKind::Bound(debruijn, ty::BoundVar::from_u32(index)),
param_ty,
)),
- Some(rbv::ResolvedArg::Error(guar)) => {
- Some(tcx.const_error_with_guaranteed(param_ty, guar))
- }
+ Some(rbv::ResolvedArg::Error(guar)) => Some(tcx.const_error(param_ty, guar)),
arg => bug!("unexpected bound var resolution for {:?}: {arg:?}", expr.hir_id),
}
}
@@ -238,7 +216,7 @@ impl<'tcx> Const<'tcx> {
if let Some(val) = self.kind().try_eval_for_typeck(tcx, param_env) {
match val {
Ok(val) => tcx.mk_const(val, self.ty()),
- Err(guar) => tcx.const_error_with_guaranteed(self.ty(), guar),
+ Err(guar) => tcx.const_error(self.ty(), guar),
}
} else {
// Either the constant isn't evaluatable or ValTree creation failed.
diff --git a/compiler/rustc_middle/src/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs
index c0e557d48..d1dbc531e 100644
--- a/compiler/rustc_middle/src/ty/consts/int.rs
+++ b/compiler/rustc_middle/src/ty/consts/int.rs
@@ -141,14 +141,18 @@ impl<CTX> crate::ty::HashStable<CTX> for ScalarInt {
impl<S: Encoder> Encodable<S> for ScalarInt {
fn encode(&self, s: &mut S) {
- s.emit_u128(self.data);
- s.emit_u8(self.size.get());
+ let size = self.size.get();
+ s.emit_u8(size);
+ s.emit_raw_bytes(&self.data.to_le_bytes()[..size as usize]);
}
}
impl<D: Decoder> Decodable<D> for ScalarInt {
fn decode(d: &mut D) -> ScalarInt {
- ScalarInt { data: d.read_u128(), size: NonZeroU8::new(d.read_u8()).unwrap() }
+ let mut data = [0u8; 16];
+ let size = d.read_u8();
+ data[..size as usize].copy_from_slice(d.read_raw_bytes(size as usize));
+ ScalarInt { data: u128::from_le_bytes(data), size: NonZeroU8::new(size).unwrap() }
}
}
diff --git a/compiler/rustc_middle/src/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs
index 560caa041..1dd4f8a24 100644
--- a/compiler/rustc_middle/src/ty/consts/kind.rs
+++ b/compiler/rustc_middle/src/ty/consts/kind.rs
@@ -17,7 +17,7 @@ use super::ScalarInt;
#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Lift)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
pub struct UnevaluatedConst<'tcx> {
- pub def: ty::WithOptConstParam<DefId>,
+ pub def: DefId,
pub substs: SubstsRef<'tcx>,
}
@@ -36,16 +36,13 @@ impl<'tcx> UnevaluatedConst<'tcx> {
impl<'tcx> UnevaluatedConst<'tcx> {
#[inline]
- pub fn new(
- def: ty::WithOptConstParam<DefId>,
- substs: SubstsRef<'tcx>,
- ) -> UnevaluatedConst<'tcx> {
+ pub fn new(def: DefId, substs: SubstsRef<'tcx>) -> UnevaluatedConst<'tcx> {
UnevaluatedConst { def, substs }
}
}
/// Represents a constant in Rust.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable)]
#[derive(Hash, HashStable, TypeFoldable, TypeVisitable)]
#[derive(derive_more::From)]
pub enum ConstKind<'tcx> {
@@ -131,7 +128,7 @@ impl<'tcx> ConstKind<'tcx> {
}
/// An inference variable for a const, for use in const generics.
-#[derive(Copy, Clone, Debug, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
+#[derive(Copy, Clone, Eq, PartialEq, PartialOrd, Ord, TyEncodable, TyDecodable, Hash)]
pub enum InferConst<'tcx> {
/// Infer the value of the const.
Var(ty::ConstVid<'tcx>),
@@ -224,9 +221,9 @@ impl<'tcx> ConstKind<'tcx> {
// FIXME(eddyb, skinny121) pass `InferCtxt` into here when it's available, so that
// we can call `infcx.const_eval_resolve` which handles inference variables.
let param_env_and = if (param_env, unevaluated).has_non_region_infer() {
- tcx.param_env(unevaluated.def.did).and(ty::UnevaluatedConst {
+ tcx.param_env(unevaluated.def).and(ty::UnevaluatedConst {
def: unevaluated.def,
- substs: InternalSubsts::identity_for_item(tcx, unevaluated.def.did),
+ substs: InternalSubsts::identity_for_item(tcx, unevaluated.def),
})
} else {
tcx.erase_regions(param_env)
@@ -248,7 +245,7 @@ impl<'tcx> ConstKind<'tcx> {
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(EvalResult::ValTree(val?))),
Err(ErrorHandled::TooGeneric) => None,
- Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+ Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
}
}
EvalMode::Mir => {
@@ -259,7 +256,7 @@ impl<'tcx> ConstKind<'tcx> {
// can leak through `val` into the const we return.
Ok(val) => Some(Ok(EvalResult::ConstVal(val))),
Err(ErrorHandled::TooGeneric) => None,
- Err(ErrorHandled::Reported(e)) => Some(Err(e)),
+ Err(ErrorHandled::Reported(e)) => Some(Err(e.into())),
}
}
}
diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs
index 63f7cc2ee..2bde55bc4 100644
--- a/compiler/rustc_middle/src/ty/context.rs
+++ b/compiler/rustc_middle/src/ty/context.rs
@@ -13,25 +13,28 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
use crate::middle::resolve_bound_vars;
use crate::middle::stability;
use crate::mir::interpret::{self, Allocation, ConstAllocation};
-use crate::mir::{Body, BorrowCheckResult, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::mir::{Body, Local, Place, PlaceElem, ProjectionKind, Promoted};
+use crate::query::plumbing::QuerySystem;
use crate::query::LocalCrate;
+use crate::query::Providers;
+use crate::query::{IntoQueryParam, TyCtxtAt};
use crate::thir::Thir;
use crate::traits;
use crate::traits::solve;
-use crate::traits::solve::{ExternalConstraints, ExternalConstraintsData};
-use crate::ty::query::{self, TyCtxtAt};
+use crate::traits::solve::{
+ ExternalConstraints, ExternalConstraintsData, PredefinedOpaques, PredefinedOpaquesData,
+};
use crate::ty::{
self, AdtDef, AdtDefData, AdtKind, Binder, Const, ConstData, FloatTy, FloatVar, FloatVid,
GenericParamDefKind, ImplPolarity, InferTy, IntTy, IntVar, IntVid, List, ParamConst, ParamTy,
PolyExistentialPredicate, PolyFnSig, Predicate, PredicateKind, Region, RegionKind, ReprOptions,
- TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, TypeckResults, UintTy, Visibility,
+ TraitObjectVisitor, Ty, TyKind, TyVar, TyVid, TypeAndMut, UintTy, Visibility,
};
use crate::ty::{GenericArg, InternalSubsts, SubstsRef};
use rustc_ast::{self as ast, attr};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::intern::Interned;
-use rustc_data_structures::memmap::Mmap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sharded::{IntoPointer, ShardedHashMap};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
@@ -50,7 +53,7 @@ use rustc_hir::lang_items::LangItem;
use rustc_hir::{
Constness, ExprKind, HirId, ImplItemKind, ItemKind, Node, TraitCandidate, TraitItemKind,
};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::dep_graph::DepNodeIndex;
use rustc_query_system::ich::StableHashingContext;
@@ -61,7 +64,6 @@ use rustc_session::lint::Lint;
use rustc_session::Limit;
use rustc_session::Session;
use rustc_span::def_id::{DefPathHash, StableCrateId};
-use rustc_span::source_map::SourceMap;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{Span, DUMMY_SP};
use rustc_target::abi::{FieldIdx, Layout, LayoutS, TargetDataLayout, VariantIdx};
@@ -82,21 +84,6 @@ use std::ops::{Bound, Deref};
const TINY_CONST_EVAL_LIMIT: Limit = Limit(20);
-pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
- /// Creates a new `OnDiskCache` instance from the serialized data in `data`.
- fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
- where
- Self: Sized;
-
- fn new_empty(source_map: &'tcx SourceMap) -> Self
- where
- Self: Sized;
-
- fn drop_serialized_data(&self, tcx: TyCtxt<'tcx>);
-
- fn serialize(&self, tcx: TyCtxt<'tcx>, encoder: FileEncoder) -> FileEncodeResult;
-}
-
#[allow(rustc::usage_of_ty_tykind)]
impl<'tcx> Interner for TyCtxt<'tcx> {
type AdtDef = ty::AdtDef<'tcx>;
@@ -141,6 +128,7 @@ pub struct CtxtInterners<'tcx> {
type_: InternedSet<'tcx, WithCachedTypeInfo<TyKind<'tcx>>>,
const_lists: InternedSet<'tcx, List<ty::Const<'tcx>>>,
substs: InternedSet<'tcx, InternalSubsts<'tcx>>,
+ type_lists: InternedSet<'tcx, List<Ty<'tcx>>>,
canonical_var_infos: InternedSet<'tcx, List<CanonicalVarInfo<'tcx>>>,
region: InternedSet<'tcx, RegionKind<'tcx>>,
poly_existential_predicates: InternedSet<'tcx, List<PolyExistentialPredicate<'tcx>>>,
@@ -154,6 +142,8 @@ pub struct CtxtInterners<'tcx> {
layout: InternedSet<'tcx, LayoutS>,
adt_def: InternedSet<'tcx, AdtDefData>,
external_constraints: InternedSet<'tcx, ExternalConstraintsData<'tcx>>,
+ predefined_opaques_in_body: InternedSet<'tcx, PredefinedOpaquesData<'tcx>>,
+ fields: InternedSet<'tcx, List<FieldIdx>>,
}
impl<'tcx> CtxtInterners<'tcx> {
@@ -163,6 +153,7 @@ impl<'tcx> CtxtInterners<'tcx> {
type_: Default::default(),
const_lists: Default::default(),
substs: Default::default(),
+ type_lists: Default::default(),
region: Default::default(),
poly_existential_predicates: Default::default(),
canonical_var_infos: Default::default(),
@@ -176,6 +167,8 @@ impl<'tcx> CtxtInterners<'tcx> {
layout: Default::default(),
adt_def: Default::default(),
external_constraints: Default::default(),
+ predefined_opaques_in_body: Default::default(),
+ fields: Default::default(),
}
}
@@ -209,7 +202,7 @@ impl<'tcx> CtxtInterners<'tcx> {
) -> Fingerprint {
// It's impossible to hash inference variables (and will ICE), so we don't need to try to cache them.
// Without incremental, we rarely stable-hash types, so let's not do it proactively.
- if flags.flags.intersects(TypeFlags::NEEDS_INFER) || sess.opts.incremental.is_none() {
+ if flags.flags.intersects(TypeFlags::HAS_INFER) || sess.opts.incremental.is_none() {
Fingerprint::ZERO
} else {
let mut hasher = StableHasher::new();
@@ -447,6 +440,14 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn feed_local_crate(self) -> TyCtxtFeed<'tcx, CrateNum> {
TyCtxtFeed { tcx: self, key: LOCAL_CRATE }
}
+
+ /// In order to break cycles involving `AnonConst`, we need to set the expected type by side
+ /// effect. However, we do not want this as a general capability, so this interface restricts
+ /// to the only allowed case.
+ pub fn feed_anon_const_type(self, key: LocalDefId, value: ty::EarlyBinder<Ty<'tcx>>) {
+ debug_assert_eq!(self.def_kind(key), DefKind::AnonConst);
+ TyCtxtFeed { tcx: self, key }.type_of(value)
+ }
}
impl<'tcx, KEY: Copy> TyCtxtFeed<'tcx, KEY> {
@@ -496,7 +497,7 @@ pub struct GlobalCtxt<'tcx> {
///
/// FIXME(Centril): consider `dyn LintStoreMarker` once
/// we can upcast to `Any` for some additional type safety.
- pub lint_store: Lrc<dyn Any + sync::Sync + sync::Send>,
+ pub lint_store: Lrc<dyn Any + sync::DynSync + sync::DynSend>,
pub dep_graph: DepGraph,
@@ -513,14 +514,7 @@ pub struct GlobalCtxt<'tcx> {
untracked: Untracked,
- /// This provides access to the incremental compilation on-disk cache for query results.
- /// Do not access this directly. It is only meant to be used by
- /// `DepGraph::try_mark_green()` and the query infrastructure.
- /// This is `None` if we are not incremental compilation mode
- pub on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
-
- pub queries: &'tcx dyn query::QueryEngine<'tcx>,
- pub query_system: query::QuerySystem<'tcx>,
+ pub query_system: QuerySystem<'tcx>,
pub(crate) query_kinds: &'tcx [DepKindStruct<'tcx>],
// Internal caches for metadata decoding. No need to track deps on this.
@@ -581,28 +575,6 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- pub fn typeck_opt_const_arg(
- self,
- def: ty::WithOptConstParam<LocalDefId>,
- ) -> &'tcx TypeckResults<'tcx> {
- if let Some(param_did) = def.const_param_did {
- self.typeck_const_arg((def.did, param_did))
- } else {
- self.typeck(def.did)
- }
- }
-
- pub fn mir_borrowck_opt_const_arg(
- self,
- def: ty::WithOptConstParam<LocalDefId>,
- ) -> &'tcx BorrowCheckResult<'tcx> {
- if let Some(param_did) = def.const_param_did {
- self.mir_borrowck_const_arg((def.did, param_did))
- } else {
- self.mir_borrowck(def.did)
- }
- }
-
pub fn alloc_steal_thir(self, thir: Thir<'tcx>) -> &'tcx Steal<Thir<'tcx>> {
self.arena.alloc(Steal::new(thir))
}
@@ -677,14 +649,13 @@ impl<'tcx> TyCtxt<'tcx> {
/// reference to the context, to allow formatting values that need it.
pub fn create_global_ctxt(
s: &'tcx Session,
- lint_store: Lrc<dyn Any + sync::Send + sync::Sync>,
+ lint_store: Lrc<dyn Any + sync::DynSend + sync::DynSync>,
arena: &'tcx WorkerLocal<Arena<'tcx>>,
hir_arena: &'tcx WorkerLocal<hir::Arena<'tcx>>,
untracked: Untracked,
dep_graph: DepGraph,
- on_disk_cache: Option<&'tcx dyn OnDiskCache<'tcx>>,
- queries: &'tcx dyn query::QueryEngine<'tcx>,
query_kinds: &'tcx [DepKindStruct<'tcx>],
+ query_system: QuerySystem<'tcx>,
) -> GlobalCtxt<'tcx> {
let data_layout = s.target.parse_data_layout().unwrap_or_else(|err| {
s.emit_fatal(err);
@@ -706,9 +677,7 @@ impl<'tcx> TyCtxt<'tcx> {
lifetimes: common_lifetimes,
consts: common_consts,
untracked,
- on_disk_cache,
- queries,
- query_system: Default::default(),
+ query_system,
query_kinds,
ty_rcache: Default::default(),
pred_rcache: Default::default(),
@@ -735,7 +704,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
/// ensure it gets used.
#[track_caller]
- pub fn ty_error_with_message<S: Into<MultiSpan>>(self, span: S, msg: &str) -> Ty<'tcx> {
+ pub fn ty_error_with_message<S: Into<MultiSpan>>(
+ self,
+ span: S,
+ msg: impl Into<DiagnosticMessage>,
+ ) -> Ty<'tcx> {
let reported = self.sess.delay_span_bug(span, msg);
self.mk_ty_from_kind(Error(reported))
}
@@ -766,17 +739,13 @@ impl<'tcx> TyCtxt<'tcx> {
/// 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> {
+ pub fn const_error(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> {
+ pub fn const_error_misc(self, ty: Ty<'tcx>) -> Const<'tcx> {
self.const_error_with_message(
ty,
DUMMY_SP,
@@ -834,7 +803,8 @@ impl<'tcx> TyCtxt<'tcx> {
self.features_query(())
}
- pub fn def_key(self, id: DefId) -> rustc_hir::definitions::DefKey {
+ pub fn def_key(self, id: impl IntoQueryParam<DefId>) -> rustc_hir::definitions::DefKey {
+ let id = id.into_query_param();
// Accessing the DefKey is ok, since it is part of DefPathHash.
if let Some(id) = id.as_local() {
self.definitions_untracked().def_key(id)
@@ -925,7 +895,7 @@ impl<'tcx> TyCtxt<'tcx> {
crate_name,
// Don't print the whole stable crate id. That's just
// annoying in debug output.
- stable_crate_id.to_u64() >> (8 * 6),
+ stable_crate_id.as_u64() >> (8 * 6),
self.def_path(def_id).to_string_no_crate_verbose()
)
}
@@ -1046,7 +1016,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn serialize_query_result_cache(self, encoder: FileEncoder) -> FileEncodeResult {
- self.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
+ self.query_system.on_disk_cache.as_ref().map_or(Ok(0), |c| c.serialize(self, encoder))
}
/// If `true`, we should use lazy normalization for constants, otherwise
@@ -1123,11 +1093,13 @@ impl<'tcx> TyCtxt<'tcx> {
v.0
}
- /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type and associated alias span when type alias is used
+ /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in
+ /// its return type, and the associated alias span when type alias is used,
+ /// along with a span for lifetime suggestion (if there are existing generics).
pub fn return_type_impl_or_dyn_traits_with_type_alias(
self,
scope_def_id: LocalDefId,
- ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span)> {
+ ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option<Span>)> {
let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id);
let mut v = TraitObjectVisitor(vec![], self.hir());
// when the return type is a type alias
@@ -1141,7 +1113,7 @@ impl<'tcx> TyCtxt<'tcx> {
{
v.visit_ty(alias_ty);
if !v.0.is_empty() {
- return Some((v.0, alias_generics.span));
+ return Some((v.0, alias_generics.span, alias_generics.span_for_lifetime_suggestion()));
}
}
return None;
@@ -1231,7 +1203,7 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn all_traits(self) -> impl Iterator<Item = DefId> + 'tcx {
iter::once(LOCAL_CRATE)
.chain(self.crates(()).iter().copied())
- .flat_map(move |cnum| self.traits_in_crate(cnum).iter().copied())
+ .flat_map(move |cnum| self.traits(cnum).iter().copied())
}
#[inline]
@@ -1278,25 +1250,6 @@ macro_rules! nop_lift {
};
}
-// Can't use the macros as we have reuse the `substs` here.
-//
-// See `mk_type_list` for more info.
-impl<'a, 'tcx> Lift<'tcx> for &'a List<Ty<'a>> {
- type Lifted = &'tcx List<Ty<'tcx>>;
- fn lift_to_tcx(self, tcx: TyCtxt<'tcx>) -> Option<Self::Lifted> {
- if self.is_empty() {
- return Some(List::empty());
- }
-
- tcx.interners
- .substs
- .contains_pointer_to(&InternedInSet(self.as_substs()))
- // SAFETY: `self` is interned and therefore valid
- // for the entire lifetime of the `TyCtxt`.
- .then(|| unsafe { mem::transmute::<&'a List<Ty<'a>>, &'tcx List<Ty<'tcx>>>(self) })
- }
-}
-
macro_rules! nop_list_lift {
($set:ident; $ty:ty => $lifted:ty) => {
impl<'a, 'tcx> Lift<'tcx> for &'a List<$ty> {
@@ -1320,6 +1273,7 @@ nop_lift! {const_; Const<'a> => Const<'tcx>}
nop_lift! {const_allocation; ConstAllocation<'a> => ConstAllocation<'tcx>}
nop_lift! {predicate; Predicate<'a> => Predicate<'tcx>}
+nop_list_lift! {type_lists; Ty<'a> => Ty<'tcx>}
nop_list_lift! {poly_existential_predicates; PolyExistentialPredicate<'a> => PolyExistentialPredicate<'tcx>}
nop_list_lift! {predicates; Predicate<'a> => Predicate<'tcx>}
nop_list_lift! {canonical_var_infos; CanonicalVarInfo<'a> => CanonicalVarInfo<'tcx>}
@@ -1329,9 +1283,12 @@ nop_list_lift! {bound_variable_kinds; ty::BoundVariableKind => ty::BoundVariable
// This is the impl for `&'a InternalSubsts<'a>`.
nop_list_lift! {substs; GenericArg<'a> => GenericArg<'tcx>}
-CloneLiftImpls! { for<'tcx> {
- Constness, traits::WellFormedLoc, ImplPolarity, crate::mir::ReturnConstraint,
-} }
+CloneLiftImpls! {
+ Constness,
+ traits::WellFormedLoc,
+ ImplPolarity,
+ crate::mir::ReturnConstraint,
+}
macro_rules! sty_debug_print {
($fmt: expr, $ctxt: expr, $($variant: ident),*) => {{
@@ -1567,6 +1524,8 @@ direct_interners! {
adt_def: pub mk_adt_def_from_data(AdtDefData): AdtDef -> AdtDef<'tcx>,
external_constraints: pub mk_external_constraints(ExternalConstraintsData<'tcx>):
ExternalConstraints -> ExternalConstraints<'tcx>,
+ predefined_opaques_in_body: pub mk_predefined_opaques_in_body(PredefinedOpaquesData<'tcx>):
+ PredefinedOpaques -> PredefinedOpaques<'tcx>,
}
macro_rules! slice_interners {
@@ -1591,12 +1550,14 @@ macro_rules! slice_interners {
slice_interners!(
const_lists: pub mk_const_list(Const<'tcx>),
substs: pub mk_substs(GenericArg<'tcx>),
+ type_lists: pub mk_type_list(Ty<'tcx>),
canonical_var_infos: pub mk_canonical_var_infos(CanonicalVarInfo<'tcx>),
poly_existential_predicates: intern_poly_existential_predicates(PolyExistentialPredicate<'tcx>),
predicates: intern_predicates(Predicate<'tcx>),
projs: pub mk_projs(ProjectionKind),
place_elems: pub mk_place_elems(PlaceElem<'tcx>),
bound_variable_kinds: pub mk_bound_variable_kinds(ty::BoundVariableKind),
+ fields: pub mk_fields(FieldIdx),
);
impl<'tcx> TyCtxt<'tcx> {
@@ -1610,11 +1571,11 @@ impl<'tcx> TyCtxt<'tcx> {
/// Given the def_id of a Trait `trait_def_id` and the name of an associated item `assoc_name`
/// returns true if the `trait_def_id` defines an associated item of name `assoc_name`.
- pub fn trait_may_define_assoc_type(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
+ pub fn trait_may_define_assoc_item(self, trait_def_id: DefId, assoc_name: Ident) -> bool {
self.super_traits_of(trait_def_id).any(|trait_did| {
self.associated_items(trait_did)
- .find_by_name_and_kind(self, assoc_name, ty::AssocKind::Type, trait_did)
- .is_some()
+ .filter_by_name_unhygienic(assoc_name.name)
+ .any(|item| self.hygienic_eq(assoc_name, item.ident(self), trait_did))
})
}
@@ -1623,7 +1584,7 @@ impl<'tcx> TyCtxt<'tcx> {
let ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) = ty.kind() else { return false };
let future_trait = self.require_lang_item(LangItem::Future, None);
- self.explicit_item_bounds(def_id).iter().any(|(predicate, _)| {
+ self.explicit_item_bounds(def_id).skip_binder().iter().any(|&(predicate, _)| {
let ty::PredicateKind::Clause(ty::Clause::Trait(trait_predicate)) = predicate.kind().skip_binder() else {
return false;
};
@@ -1881,7 +1842,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
#[inline(always)]
- fn check_and_mk_substs(
+ pub(crate) fn check_and_mk_substs(
self,
_def_id: DefId,
substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
@@ -1889,7 +1850,17 @@ impl<'tcx> TyCtxt<'tcx> {
let substs = substs.into_iter().map(Into::into);
#[cfg(debug_assertions)]
{
- let n = self.generics_of(_def_id).count();
+ let generics = self.generics_of(_def_id);
+
+ let n = if let DefKind::AssocTy = self.def_kind(_def_id)
+ && let DefKind::Impl { of_trait: false } = self.def_kind(self.parent(_def_id))
+ {
+ // If this is an inherent projection.
+
+ generics.params.len() + 1
+ } else {
+ generics.count()
+ };
assert_eq!(
(n, Some(n)),
substs.size_hint(),
@@ -2050,7 +2021,7 @@ impl<'tcx> TyCtxt<'tcx> {
debug_assert_matches!(
(kind, self.def_kind(alias_ty.def_id)),
(ty::Opaque, DefKind::OpaqueTy)
- | (ty::Projection, DefKind::AssocTy)
+ | (ty::Projection | ty::Inherent, DefKind::AssocTy)
| (ty::Opaque | ty::Projection, DefKind::ImplTraitPlaceholder)
);
self.mk_ty_from_kind(Alias(kind, alias_ty))
@@ -2190,18 +2161,6 @@ impl<'tcx> TyCtxt<'tcx> {
T::collect_and_apply(iter, |xs| self.mk_const_list(xs))
}
- pub fn mk_type_list(self, ts: &[Ty<'tcx>]) -> &'tcx List<Ty<'tcx>> {
- // Actually intern type lists as lists of `GenericArg`s.
- //
- // Transmuting from `Ty<'tcx>` to `GenericArg<'tcx>` is sound
- // as explained in `ty_slice_as_generic_arg`. With this,
- // we guarantee that even when transmuting between `List<Ty<'tcx>>`
- // and `List<GenericArg<'tcx>>`, the uniqueness requirement for
- // lists is upheld.
- let substs = self.mk_substs(ty::subst::ty_slice_as_generic_args(ts));
- substs.try_as_type_list().unwrap()
- }
-
// Unlike various other `mk_*_from_iter` functions, this one uses `I:
// IntoIterator` instead of `I: Iterator`, and it doesn't have a slice
// variant, because of the need to combine `inputs` and `output`. This
@@ -2277,6 +2236,14 @@ impl<'tcx> TyCtxt<'tcx> {
T::collect_and_apply(iter, |xs| self.mk_place_elems(xs))
}
+ pub fn mk_fields_from_iter<I, T>(self, iter: I) -> T::Output
+ where
+ I: Iterator<Item = T>,
+ T: CollectAndApply<FieldIdx, &'tcx List<FieldIdx>>,
+ {
+ T::collect_and_apply(iter, |xs| self.mk_fields(xs))
+ }
+
pub fn mk_substs_trait(
self,
self_ty: Ty<'tcx>,
@@ -2285,15 +2252,6 @@ impl<'tcx> TyCtxt<'tcx> {
self.mk_substs_from_iter(iter::once(self_ty.into()).chain(rest))
}
- pub fn mk_trait_ref(
- self,
- trait_def_id: DefId,
- substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
- ) -> ty::TraitRef<'tcx> {
- let substs = self.check_and_mk_substs(trait_def_id, substs);
- ty::TraitRef { def_id: trait_def_id, substs, _use_mk_trait_ref_instead: () }
- }
-
pub fn mk_alias_ty(
self,
def_id: DefId,
@@ -2389,7 +2347,7 @@ impl<'tcx> TyCtxt<'tcx> {
}
pub fn is_late_bound(self, id: HirId) -> bool {
- self.is_late_bound_map(id.owner).map_or(false, |set| set.contains(&id.local_id))
+ self.is_late_bound_map(id.owner).is_some_and(|set| set.contains(&id.local_id))
}
pub fn late_bound_vars(self, id: HirId) -> &'tcx List<ty::BoundVariableKind> {
@@ -2461,26 +2419,17 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- /// Named module children from all items except `use` and `extern crate` imports.
- ///
- /// In addition to regular items this list also includes struct or variant constructors, and
+ /// Named module children from all kinds of items, including imports.
+ /// In addition to regular items this list also includes struct and variant constructors, and
/// items inside `extern {}` blocks because all of them introduce names into parent module.
- /// For non-reexported children every such name is associated with a separate `DefId`.
///
/// Module here is understood in name resolution sense - it can be a `mod` item,
/// or a crate root, or an enum, or a trait.
- pub fn module_children_non_reexports(self, def_id: LocalDefId) -> &'tcx [LocalDefId] {
- self.resolutions(()).module_children_non_reexports.get(&def_id).map_or(&[], |v| &v[..])
- }
-
- /// Named module children from `use` and `extern crate` imports.
///
- /// Reexported names are not associated with individual `DefId`s,
- /// e.g. a glob import can introduce a lot of names, all with the same `DefId`.
- /// That's why the list needs to contain `ModChild` structures describing all the names
- /// individually instead of `DefId`s.
- pub fn module_children_reexports(self, def_id: LocalDefId) -> &'tcx [ModChild] {
- self.resolutions(()).module_children_reexports.get(&def_id).map_or(&[], |v| &v[..])
+ /// This is not a query, making it a query causes perf regressions
+ /// (probably due to hashing spans in `ModChild`ren).
+ pub fn module_children_local(self, def_id: LocalDefId) -> &'tcx [ModChild] {
+ self.resolutions(()).module_children.get(&def_id).map_or(&[], |v| &v[..])
}
}
@@ -2494,18 +2443,9 @@ impl<'tcx> TyCtxtAt<'tcx> {
/// Constructs a `TyKind::Error` type and registers a `delay_span_bug` with the given `msg` to
/// ensure it gets used.
#[track_caller]
- pub fn ty_error_with_message(self, msg: &str) -> Ty<'tcx> {
+ pub fn ty_error_with_message(self, msg: impl Into<DiagnosticMessage>) -> Ty<'tcx> {
self.tcx.ty_error_with_message(self.span, msg)
}
-
- pub fn mk_trait_ref(
- self,
- trait_lang_item: LangItem,
- substs: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
- ) -> ty::TraitRef<'tcx> {
- let trait_def_id = self.require_lang_item(trait_lang_item, Some(self.span));
- self.tcx.mk_trait_ref(trait_def_id, substs)
- }
}
/// Parameter attributes that can only be determined by examining the body of a function instead
@@ -2523,7 +2463,7 @@ pub struct DeducedParamAttrs {
pub read_only: bool,
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
providers.maybe_unused_trait_imports =
|tcx, ()| &tcx.resolutions(()).maybe_unused_trait_imports;
providers.names_imported_by_glob_use = |tcx, id| {
@@ -2540,7 +2480,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
|tcx, LocalCrate| attr::contains_name(tcx.hir().krate_attrs(), sym::compiler_builtins);
providers.has_panic_handler = |tcx, LocalCrate| {
// We want to check if the panic handler was defined in this crate
- tcx.lang_items().panic_impl().map_or(false, |did| did.is_local())
+ tcx.lang_items().panic_impl().is_some_and(|did| did.is_local())
};
providers.source_span = |tcx, def_id| tcx.untracked.source_span.get(def_id).unwrap_or(DUMMY_SP);
}
diff --git a/compiler/rustc_middle/src/ty/context/tls.rs b/compiler/rustc_middle/src/ty/context/tls.rs
index fb0d90930..9de77b9fd 100644
--- a/compiler/rustc_middle/src/ty/context/tls.rs
+++ b/compiler/rustc_middle/src/ty/context/tls.rs
@@ -1,7 +1,7 @@
use super::{GlobalCtxt, TyCtxt};
use crate::dep_graph::TaskDepsRef;
-use crate::ty::query;
+use crate::query::plumbing::QueryJobId;
use rustc_data_structures::sync::{self, Lock};
use rustc_errors::Diagnostic;
#[cfg(not(parallel_compiler))]
@@ -22,7 +22,7 @@ pub struct ImplicitCtxt<'a, 'tcx> {
/// The current query job, if any. This is updated by `JobOwner::start` in
/// `ty::query::plumbing` when executing a query.
- pub query: Option<query::QueryJobId>,
+ pub query: Option<QueryJobId>,
/// Where to store diagnostics for the current query job, if any.
/// This is updated by `JobOwner::start` in `ty::query::plumbing` when executing a query.
@@ -78,7 +78,7 @@ where
{
TLV.with(|tlv| {
let old = tlv.replace(erase(context));
- let _reset = rustc_data_structures::OnDrop(move || tlv.set(old));
+ let _reset = rustc_data_structures::defer(move || tlv.set(old));
f()
})
}
@@ -94,8 +94,8 @@ where
f(None)
} else {
// We could get an `ImplicitCtxt` pointer from another thread.
- // Ensure that `ImplicitCtxt` is `Sync`.
- sync::assert_sync::<ImplicitCtxt<'_, '_>>();
+ // Ensure that `ImplicitCtxt` is `DynSync`.
+ sync::assert_dyn_sync::<ImplicitCtxt<'_, '_>>();
unsafe { f(Some(downcast(context))) }
}
diff --git a/compiler/rustc_middle/src/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs
index ae0bb4949..6a29063b8 100644
--- a/compiler/rustc_middle/src/ty/diagnostics.rs
+++ b/compiler/rustc_middle/src/ty/diagnostics.rs
@@ -139,7 +139,7 @@ pub fn suggest_arbitrary_trait_bound<'tcx>(
// Suggest a where clause bound for a non-type parameter.
err.span_suggestion_verbose(
generics.tail_span_for_predicate_suggestion(),
- &format!(
+ format!(
"consider {} `where` clause, but there might be an alternative better way to express \
this requirement",
if generics.where_clause_span.is_empty() { "introducing a" } else { "extending the" },
@@ -242,7 +242,7 @@ pub fn suggest_constraining_type_params<'a>(
err.span_label(
param.span,
- &format!("this type parameter needs to be `{}`", constraint),
+ format!("this type parameter needs to be `{}`", constraint),
);
suggest_removing_unsized_bound(generics, &mut suggestions, param, def_id);
}
diff --git a/compiler/rustc_middle/src/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs
index 383773248..7895993cc 100644
--- a/compiler/rustc_middle/src/ty/erase_regions.rs
+++ b/compiler/rustc_middle/src/ty/erase_regions.rs
@@ -1,8 +1,9 @@
+use crate::query::Providers;
use crate::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable};
use crate::ty::{self, Ty, TyCtxt, TypeFlags, TypeVisitableExt};
-pub(super) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { erase_regions_ty, ..*providers };
+pub(super) fn provide(providers: &mut Providers) {
+ *providers = Providers { erase_regions_ty, ..*providers };
}
fn erase_regions_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> {
@@ -40,7 +41,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for RegionEraserVisitor<'tcx> {
}
fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> {
- if ty.needs_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
+ if ty.has_infer() { ty.super_fold_with(self) } else { self.tcx.erase_regions_ty(ty) }
}
fn fold_binder<T>(&mut self, t: ty::Binder<'tcx, T>) -> ty::Binder<'tcx, T>
diff --git a/compiler/rustc_middle/src/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs
index aff6c77e0..49ab9b79e 100644
--- a/compiler/rustc_middle/src/ty/error.rs
+++ b/compiler/rustc_middle/src/ty/error.rs
@@ -28,7 +28,7 @@ impl<T> ExpectedFound<T> {
}
// Data structures used in type unification
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, PartialEq, Eq)]
+#[derive(Copy, Clone, Debug, TypeVisitable, Lift, PartialEq, Eq)]
#[rustc_pass_by_value]
pub enum TypeError<'tcx> {
Mismatch,
@@ -265,7 +265,7 @@ impl<'tcx> Ty<'tcx> {
ty::Infer(ty::FreshTy(_)) => "fresh type".into(),
ty::Infer(ty::FreshIntTy(_)) => "fresh integral type".into(),
ty::Infer(ty::FreshFloatTy(_)) => "fresh floating-point type".into(),
- ty::Alias(ty::Projection, _) => "associated type".into(),
+ ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
ty::Param(p) => format!("type parameter `{p}`").into(),
ty::Alias(ty::Opaque, ..) => if tcx.ty_is_opaque_future(self) { "future".into() } else { "opaque type".into() },
ty::Error(_) => "type error".into(),
@@ -312,7 +312,7 @@ impl<'tcx> Ty<'tcx> {
ty::Tuple(..) => "tuple".into(),
ty::Placeholder(..) => "higher-ranked type".into(),
ty::Bound(..) => "bound type variable".into(),
- ty::Alias(ty::Projection, _) => "associated type".into(),
+ ty::Alias(ty::Projection | ty::Inherent, _) => "associated type".into(),
ty::Param(_) => "type parameter".into(),
ty::Alias(ty::Opaque, ..) => "opaque type".into(),
}
diff --git a/compiler/rustc_middle/src/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs
index 31d00b65e..76f61d9ac 100644
--- a/compiler/rustc_middle/src/ty/fast_reject.rs
+++ b/compiler/rustc_middle/src/ty/fast_reject.rs
@@ -68,7 +68,7 @@ pub enum TreatParams {
}
/// During fast-rejection, we have the choice of treating projection types
-/// as either simplifyable or not, depending on whether we expect the projection
+/// as either simplifiable or not, depending on whether we expect the projection
/// to be normalized/rigid.
#[derive(PartialEq, Eq, Debug, Clone, Copy)]
pub enum TreatProjections {
diff --git a/compiler/rustc_middle/src/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs
index 5a6ee1238..d64875a9f 100644
--- a/compiler/rustc_middle/src/ty/flags.rs
+++ b/compiler/rustc_middle/src/ty/flags.rs
@@ -176,14 +176,14 @@ impl FlagComputation {
self.add_substs(substs);
}
- &ty::Alias(ty::Projection, data) => {
- self.add_flags(TypeFlags::HAS_TY_PROJECTION);
- self.add_projection_ty(data);
- }
+ &ty::Alias(kind, data) => {
+ self.add_flags(match kind {
+ ty::Projection => TypeFlags::HAS_TY_PROJECTION,
+ ty::Inherent => TypeFlags::HAS_TY_INHERENT,
+ ty::Opaque => TypeFlags::HAS_TY_OPAQUE,
+ });
- &ty::Alias(ty::Opaque, ty::AliasTy { substs, .. }) => {
- self.add_flags(TypeFlags::HAS_TY_OPAQUE);
- self.add_substs(substs);
+ self.add_alias_ty(data);
}
&ty::Dynamic(obj, r, _) => {
@@ -267,7 +267,7 @@ impl FlagComputation {
projection_ty,
term,
})) => {
- self.add_projection_ty(projection_ty);
+ self.add_alias_ty(projection_ty);
self.add_term(term);
}
ty::PredicateKind::WellFormed(arg) => {
@@ -372,8 +372,8 @@ impl FlagComputation {
}
}
- fn add_projection_ty(&mut self, projection_ty: ty::AliasTy<'_>) {
- self.add_substs(projection_ty.substs);
+ fn add_alias_ty(&mut self, alias_ty: ty::AliasTy<'_>) {
+ self.add_substs(alias_ty.substs);
}
fn add_substs(&mut self, substs: &[GenericArg<'_>]) {
diff --git a/compiler/rustc_middle/src/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs
index 203e16bea..25890eb15 100644
--- a/compiler/rustc_middle/src/ty/fold.rs
+++ b/compiler/rustc_middle/src/ty/fold.rs
@@ -37,7 +37,8 @@ where
}
fn fold_region(&mut self, r: ty::Region<'tcx>) -> ty::Region<'tcx> {
- let r = r.super_fold_with(self);
+ // This one is a little different, because `super_fold_with` is not
+ // implemented on non-recursive `Region`.
(self.lt_op)(r)
}
diff --git a/compiler/rustc_middle/src/ty/generics.rs b/compiler/rustc_middle/src/ty/generics.rs
index baef4ffed..b0ffe7829 100644
--- a/compiler/rustc_middle/src/ty/generics.rs
+++ b/compiler/rustc_middle/src/ty/generics.rs
@@ -103,7 +103,7 @@ impl GenericParamDef {
ty::GenericParamDefKind::Lifetime => tcx.mk_re_error_misc().into(),
ty::GenericParamDefKind::Type { .. } => tcx.ty_error_misc().into(),
ty::GenericParamDefKind::Const { .. } => {
- tcx.const_error(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into()
+ tcx.const_error_misc(tcx.type_of(self.def_id).subst(tcx, preceding_substs)).into()
}
}
}
@@ -298,7 +298,7 @@ impl<'tcx> Generics {
.iter()
.rev()
.take_while(|param| {
- param.default_value(tcx).map_or(false, |default| {
+ param.default_value(tcx).is_some_and(|default| {
default.subst(tcx, substs) == substs[param.index as usize]
})
})
diff --git a/compiler/rustc_middle/src/ty/impls_ty.rs b/compiler/rustc_middle/src/ty/impls_ty.rs
index 4c7822acd..02baa395c 100644
--- a/compiler/rustc_middle/src/ty/impls_ty.rs
+++ b/compiler/rustc_middle/src/ty/impls_ty.rs
@@ -73,34 +73,6 @@ impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArg<'t
}
}
-impl<'a, 'tcx> HashStable<StableHashingContext<'a>> for ty::subst::GenericArgKind<'tcx> {
- fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
- match self {
- // WARNING: We dedup cache the `HashStable` results for `List`
- // while ignoring types and freely transmute
- // between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
- // See `fn mk_type_list` for more details.
- //
- // We therefore hash types without adding a hash for their discriminant.
- //
- // In order to make it very unlikely for the sequence of bytes being hashed for
- // a `GenericArgKind::Type` to be the same as the sequence of bytes being
- // hashed for one of the other variants, we hash some very high number instead
- // of their actual discriminant since `TyKind` should never start with anything
- // that high.
- ty::subst::GenericArgKind::Type(ty) => ty.hash_stable(hcx, hasher),
- ty::subst::GenericArgKind::Const(ct) => {
- 0xF3u8.hash_stable(hcx, hasher);
- ct.hash_stable(hcx, hasher);
- }
- ty::subst::GenericArgKind::Lifetime(lt) => {
- 0xF5u8.hash_stable(hcx, hasher);
- lt.hash_stable(hcx, hasher);
- }
- }
- }
-}
-
// AllocIds get resolved to whatever they point to (to be stable)
impl<'a> HashStable<StableHashingContext<'a>> for mir::interpret::AllocId {
fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) {
diff --git a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
index 92a040068..422350284 100644
--- a/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
+++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs
@@ -43,6 +43,7 @@
//! This code should only compile in modules where the uninhabitedness of `Foo`
//! is visible.
+use crate::query::Providers;
use crate::ty::context::TyCtxt;
use crate::ty::{self, DefId, Ty, VariantDef, Visibility};
@@ -52,9 +53,8 @@ pub mod inhabited_predicate;
pub use inhabited_predicate::InhabitedPredicate;
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers { inhabited_predicate_adt, inhabited_predicate_type, ..*providers };
}
/// Returns an `InhabitedPredicate` that is generic over type parameters and
@@ -113,6 +113,12 @@ impl<'tcx> Ty<'tcx> {
}
Never => InhabitedPredicate::False,
Param(_) | Alias(ty::Projection, _) => InhabitedPredicate::GenericType(self),
+ // FIXME(inherent_associated_types): Most likely we can just map to `GenericType` like above.
+ // However it's unclear if the substs passed to `InhabitedPredicate::subst` are of the correct
+ // format, i.e. don't contain parent substs. If you hit this case, please verify this beforehand.
+ Alias(ty::Inherent, _) => {
+ bug!("unimplemented: inhabitedness checking for inherent projections")
+ }
Tuple(tys) if tys.is_empty() => InhabitedPredicate::True,
// use a query for more complex cases
Adt(..) | Array(..) | Tuple(_) => tcx.inhabited_predicate_type(self),
diff --git a/compiler/rustc_middle/src/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs
index e73225f70..e641d1ef1 100644
--- a/compiler/rustc_middle/src/ty/instance.rs
+++ b/compiler/rustc_middle/src/ty/instance.rs
@@ -34,7 +34,7 @@ pub enum InstanceDef<'tcx> {
/// - `fn` items
/// - closures
/// - generators
- Item(ty::WithOptConstParam<DefId>),
+ Item(DefId),
/// An intrinsic `fn` item (with `"rust-intrinsic"` or `"platform-intrinsic"` ABI).
///
@@ -115,7 +115,7 @@ impl<'tcx> Instance<'tcx> {
/// lifetimes erased, allowing a `ParamEnv` to be specified for use during normalization.
pub fn ty(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> Ty<'tcx> {
let ty = tcx.type_of(self.def.def_id());
- tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty.skip_binder())
+ tcx.subst_and_normalize_erasing_regions(self.substs, param_env, ty)
}
/// Finds a crate that contains a monomorphization of this instance that
@@ -143,7 +143,7 @@ impl<'tcx> Instance<'tcx> {
match self.def {
InstanceDef::Item(def) => tcx
- .upstream_monomorphizations_for(def.did)
+ .upstream_monomorphizations_for(def)
.and_then(|monos| monos.get(&self.substs).cloned()),
InstanceDef::DropGlue(_, Some(_)) => tcx.upstream_drop_glue_for(self.substs),
_ => None,
@@ -155,8 +155,8 @@ impl<'tcx> InstanceDef<'tcx> {
#[inline]
pub fn def_id(self) -> DefId {
match self {
- InstanceDef::Item(def) => def.did,
- InstanceDef::VTableShim(def_id)
+ InstanceDef::Item(def_id)
+ | InstanceDef::VTableShim(def_id)
| InstanceDef::ReifyShim(def_id)
| InstanceDef::FnPtrShim(def_id, _)
| InstanceDef::Virtual(def_id, _)
@@ -172,7 +172,7 @@ impl<'tcx> InstanceDef<'tcx> {
/// Returns the `DefId` of instances which might not require codegen locally.
pub fn def_id_if_not_guaranteed_local_codegen(self) -> Option<DefId> {
match self {
- ty::InstanceDef::Item(def) => Some(def.did),
+ ty::InstanceDef::Item(def) => Some(def),
ty::InstanceDef::DropGlue(def_id, Some(_)) | InstanceDef::ThreadLocalShim(def_id) => {
Some(def_id)
}
@@ -189,23 +189,6 @@ impl<'tcx> InstanceDef<'tcx> {
}
#[inline]
- pub fn with_opt_param(self) -> ty::WithOptConstParam<DefId> {
- match self {
- InstanceDef::Item(def) => def,
- InstanceDef::VTableShim(def_id)
- | InstanceDef::ReifyShim(def_id)
- | InstanceDef::FnPtrShim(def_id, _)
- | InstanceDef::Virtual(def_id, _)
- | InstanceDef::Intrinsic(def_id)
- | InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
- | InstanceDef::DropGlue(def_id, _)
- | InstanceDef::CloneShim(def_id, _)
- | InstanceDef::ThreadLocalShim(def_id)
- | InstanceDef::FnPtrAddrShim(def_id, _) => ty::WithOptConstParam::unknown(def_id),
- }
- }
-
- #[inline]
pub fn get_attrs(
&self,
tcx: TyCtxt<'tcx>,
@@ -222,7 +205,7 @@ impl<'tcx> InstanceDef<'tcx> {
pub fn requires_inline(&self, tcx: TyCtxt<'tcx>) -> bool {
use rustc_hir::definitions::DefPathData;
let def_id = match *self {
- ty::InstanceDef::Item(def) => def.did,
+ ty::InstanceDef::Item(def) => def,
ty::InstanceDef::DropGlue(_, Some(_)) => return false,
ty::InstanceDef::ThreadLocalShim(_) => return false,
_ => return true,
@@ -273,8 +256,7 @@ impl<'tcx> InstanceDef<'tcx> {
pub fn requires_caller_location(&self, tcx: TyCtxt<'_>) -> bool {
match *self {
- InstanceDef::Item(ty::WithOptConstParam { did: def_id, .. })
- | InstanceDef::Virtual(def_id, _) => {
+ InstanceDef::Item(def_id) | InstanceDef::Virtual(def_id, _) => {
tcx.body_codegen_attrs(def_id).flags.contains(CodegenFnAttrFlags::TRACK_CALLER)
}
InstanceDef::ClosureOnceShim { call_once: _, track_caller } => track_caller,
@@ -358,7 +340,7 @@ impl<'tcx> Instance<'tcx> {
def_id,
substs
);
- Instance { def: InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)), substs }
+ Instance { def: InstanceDef::Item(def_id), substs }
}
pub fn mono(tcx: TyCtxt<'tcx>, def_id: DefId) -> Instance<'tcx> {
@@ -403,18 +385,21 @@ impl<'tcx> Instance<'tcx> {
/// couldn't complete due to errors elsewhere - this is distinct
/// from `Ok(None)` to avoid misleading diagnostics when an error
/// has already been/will be emitted, for the original cause
+ #[instrument(level = "debug", skip(tcx), ret)]
pub fn resolve(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
def_id: DefId,
substs: SubstsRef<'tcx>,
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
- Instance::resolve_opt_const_arg(
- tcx,
- param_env,
- ty::WithOptConstParam::unknown(def_id),
- substs,
- )
+ // All regions in the result of this query are erased, so it's
+ // fine to erase all of the input regions.
+
+ // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
+ // below is more likely to ignore the bounds in scope (e.g. if the only
+ // generic parameters mentioned by `substs` were lifetime ones).
+ let substs = tcx.erase_regions(substs);
+ tcx.resolve_instance(tcx.erase_regions(param_env.and((def_id, substs))))
}
pub fn expect_resolve(
@@ -432,31 +417,6 @@ impl<'tcx> Instance<'tcx> {
}
}
- // This should be kept up to date with `resolve`.
- pub fn resolve_opt_const_arg(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- def: ty::WithOptConstParam<DefId>,
- substs: SubstsRef<'tcx>,
- ) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
- // All regions in the result of this query are erased, so it's
- // fine to erase all of the input regions.
-
- // HACK(eddyb) erase regions in `substs` first, so that `param_env.and(...)`
- // below is more likely to ignore the bounds in scope (e.g. if the only
- // generic parameters mentioned by `substs` were lifetime ones).
- let substs = tcx.erase_regions(substs);
-
- // FIXME(eddyb) should this always use `param_env.with_reveal_all()`?
- if let Some((did, param_did)) = def.as_const_arg() {
- tcx.resolve_instance_of_const_arg(
- tcx.erase_regions(param_env.and((did, param_did, substs))),
- )
- } else {
- tcx.resolve_instance(tcx.erase_regions(param_env.and((def.did, substs))))
- }
- }
-
pub fn resolve_for_fn_ptr(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -470,7 +430,7 @@ impl<'tcx> Instance<'tcx> {
match resolved.def {
InstanceDef::Item(def) if resolved.def.requires_caller_location(tcx) => {
debug!(" => fn pointer created for function with #[track_caller]");
- resolved.def = InstanceDef::ReifyShim(def.did);
+ resolved.def = InstanceDef::ReifyShim(def);
}
InstanceDef::Virtual(def_id, _) => {
debug!(" => fn pointer created for virtual call");
@@ -513,23 +473,23 @@ impl<'tcx> Instance<'tcx> {
if resolved.def.requires_caller_location(tcx)
// 2) The caller location parameter comes from having `#[track_caller]`
// on the implementation, and *not* on the trait method.
- && !tcx.should_inherit_track_caller(def.did)
+ && !tcx.should_inherit_track_caller(def)
// If the method implementation comes from the trait definition itself
// (e.g. `trait Foo { #[track_caller] my_fn() { /* impl */ } }`),
// then we don't need to generate a shim. This check is needed because
// `should_inherit_track_caller` returns `false` if our method
// implementation comes from the trait block, and not an impl block
&& !matches!(
- tcx.opt_associated_item(def.did),
+ tcx.opt_associated_item(def),
Some(ty::AssocItem {
container: ty::AssocItemContainer::TraitContainer,
..
})
)
{
- if tcx.is_closure(def.did) {
+ if tcx.is_closure(def) {
debug!(" => vtable fn pointer created for closure with #[track_caller]: {:?} for method {:?} {:?}",
- def.did, def_id, substs);
+ def, def_id, substs);
// Create a shim for the `FnOnce/FnMut/Fn` method we are calling
// - unlike functions, invoking a closure always goes through a
@@ -537,9 +497,9 @@ impl<'tcx> Instance<'tcx> {
resolved = Instance { def: InstanceDef::ReifyShim(def_id), substs };
} else {
debug!(
- " => vtable fn pointer created for function with #[track_caller]: {:?}", def.did
+ " => vtable fn pointer created for function with #[track_caller]: {:?}", def
);
- resolved.def = InstanceDef::ReifyShim(def.did);
+ resolved.def = InstanceDef::ReifyShim(def);
}
}
}
@@ -618,14 +578,15 @@ impl<'tcx> Instance<'tcx> {
self.def.has_polymorphic_mir_body().then_some(self.substs)
}
- pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: &T) -> T
+ pub fn subst_mir<T>(&self, tcx: TyCtxt<'tcx>, v: EarlyBinder<&T>) -> T
where
T: TypeFoldable<TyCtxt<'tcx>> + Copy,
{
+ let v = v.map_bound(|v| *v);
if let Some(substs) = self.substs_for_mir_body() {
- EarlyBinder(*v).subst(tcx, substs)
+ v.subst(tcx, substs)
} else {
- *v
+ v.skip_binder()
}
}
@@ -634,7 +595,7 @@ impl<'tcx> Instance<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- v: T,
+ v: EarlyBinder<T>,
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
@@ -642,7 +603,7 @@ impl<'tcx> Instance<'tcx> {
if let Some(substs) = self.substs_for_mir_body() {
tcx.subst_and_normalize_erasing_regions(substs, param_env, v)
} else {
- tcx.normalize_erasing_regions(param_env, v)
+ tcx.normalize_erasing_regions(param_env, v.skip_binder())
}
}
@@ -651,7 +612,7 @@ impl<'tcx> Instance<'tcx> {
&self,
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- v: T,
+ v: EarlyBinder<T>,
) -> Result<T, NormalizationError<'tcx>>
where
T: TypeFoldable<TyCtxt<'tcx>> + Clone,
@@ -659,7 +620,7 @@ impl<'tcx> Instance<'tcx> {
if let Some(substs) = self.substs_for_mir_body() {
tcx.try_subst_and_normalize_erasing_regions(substs, param_env, v)
} else {
- tcx.try_normalize_erasing_regions(param_env, v)
+ tcx.try_normalize_erasing_regions(param_env, v.skip_binder())
}
}
@@ -698,7 +659,7 @@ fn polymorphize<'tcx>(
} else {
None
};
- let has_upvars = upvars_ty.map_or(false, |ty| !ty.tuple_fields().is_empty());
+ let has_upvars = upvars_ty.is_some_and(|ty| !ty.tuple_fields().is_empty());
debug!("polymorphize: upvars_ty={:?} has_upvars={:?}", upvars_ty, has_upvars);
struct PolymorphizationFolder<'tcx> {
@@ -714,11 +675,8 @@ fn polymorphize<'tcx>(
debug!("fold_ty: ty={:?}", ty);
match *ty.kind() {
ty::Closure(def_id, substs) => {
- let polymorphized_substs = polymorphize(
- self.tcx,
- ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
- substs,
- );
+ let polymorphized_substs =
+ polymorphize(self.tcx, ty::InstanceDef::Item(def_id), substs);
if substs == polymorphized_substs {
ty
} else {
@@ -726,11 +684,8 @@ fn polymorphize<'tcx>(
}
}
ty::Generator(def_id, substs, movability) => {
- let polymorphized_substs = polymorphize(
- self.tcx,
- ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id)),
- substs,
- );
+ let polymorphized_substs =
+ polymorphize(self.tcx, ty::InstanceDef::Item(def_id), substs);
if substs == polymorphized_substs {
ty
} else {
diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs
index 195d951f9..b5a743cfe 100644
--- a/compiler/rustc_middle/src/ty/layout.rs
+++ b/compiler/rustc_middle/src/ty/layout.rs
@@ -1,11 +1,12 @@
use crate::fluent_generated as fluent;
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
+use crate::query::TyCtxtAt;
use crate::ty::normalize_erasing_regions::NormalizationError;
use crate::ty::{self, ReprOptions, Ty, TyCtxt, TypeVisitableExt};
use rustc_errors::{DiagnosticBuilder, Handler, IntoDiagnostic};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_session::config::OptLevel;
use rustc_span::symbol::{sym, Symbol};
use rustc_span::{Span, DUMMY_SP};
@@ -210,6 +211,7 @@ pub enum LayoutError<'tcx> {
Unknown(Ty<'tcx>),
SizeOverflow(Ty<'tcx>),
NormalizationFailure(Ty<'tcx>, NormalizationError<'tcx>),
+ Cycle,
}
impl IntoDiagnostic<'_, !> for LayoutError<'_> {
@@ -230,12 +232,15 @@ impl IntoDiagnostic<'_, !> for LayoutError<'_> {
diag.set_arg("failure_ty", e.get_type_for_failure());
diag.set_primary_message(fluent::middle_cannot_be_normalized);
}
+ LayoutError::Cycle => {
+ diag.set_primary_message(fluent::middle_cycle);
+ }
}
diag
}
}
-// FIXME: Once the other errors that embed this error have been converted to translateable
+// FIXME: Once the other errors that embed this error have been converted to translatable
// diagnostics, this Display impl should be removed.
impl<'tcx> fmt::Display for LayoutError<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
@@ -250,6 +255,7 @@ impl<'tcx> fmt::Display for LayoutError<'tcx> {
t,
e.get_type_for_failure()
),
+ LayoutError::Cycle => write!(f, "a cycle occurred during layout computation"),
}
}
}
@@ -263,7 +269,7 @@ pub struct LayoutCx<'tcx, C> {
impl<'tcx> LayoutCalculator for LayoutCx<'tcx, TyCtxt<'tcx>> {
type TargetDataLayoutRef = &'tcx TargetDataLayout;
- fn delay_bug(&self, txt: &str) {
+ fn delay_bug(&self, txt: String) {
self.tcx.sess.delay_span_bug(DUMMY_SP, txt);
}
@@ -319,7 +325,7 @@ impl<'tcx> SizeSkeleton<'tcx> {
let non_zero = !ty.is_unsafe_ptr();
let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env);
match tail.kind() {
- ty::Param(_) | ty::Alias(ty::Projection, _) => {
+ ty::Param(_) | ty::Alias(ty::Projection | ty::Inherent, _) => {
debug_assert!(tail.has_non_region_param());
Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(tail) })
}
@@ -458,10 +464,10 @@ impl<'tcx> SizeSkeleton<'tcx> {
}
}
-/// When creating the layout for types with abstract conts in their size (i.e. [usize; 4 * N]),
+/// When creating the layout for types with abstract consts in their size (i.e. [usize; 4 * N]),
/// to ensure that they have a canonical order and can be compared directly we combine all
/// constants, and sort the other terms. This allows comparison of expressions of sizes,
-/// allowing for things like transmutating between types that depend on generic consts.
+/// allowing for things like transmuting between types that depend on generic consts.
/// This returns `None` if multiplication of constants overflows.
fn mul_sorted_consts<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -538,20 +544,20 @@ impl<'tcx> HasTyCtxt<'tcx> for TyCtxt<'tcx> {
}
}
-impl<'tcx> HasDataLayout for ty::query::TyCtxtAt<'tcx> {
+impl<'tcx> HasDataLayout for TyCtxtAt<'tcx> {
#[inline]
fn data_layout(&self) -> &TargetDataLayout {
&self.data_layout
}
}
-impl<'tcx> HasTargetSpec for ty::query::TyCtxtAt<'tcx> {
+impl<'tcx> HasTargetSpec for TyCtxtAt<'tcx> {
fn target_spec(&self) -> &Target {
&self.sess.target
}
}
-impl<'tcx> HasTyCtxt<'tcx> for ty::query::TyCtxtAt<'tcx> {
+impl<'tcx> HasTyCtxt<'tcx> for TyCtxtAt<'tcx> {
#[inline]
fn tcx(&self) -> TyCtxt<'tcx> {
**self
@@ -678,7 +684,7 @@ impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxt<'tcx>> {
}
}
-impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, ty::query::TyCtxtAt<'tcx>> {
+impl<'tcx> LayoutOfHelpers<'tcx> for LayoutCx<'tcx, TyCtxtAt<'tcx>> {
type LayoutOfResult = Result<TyAndLayout<'tcx>, LayoutError<'tcx>>;
#[inline]
diff --git a/compiler/rustc_middle/src/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs
index 79365ef28..71911a5a6 100644
--- a/compiler/rustc_middle/src/ty/list.rs
+++ b/compiler/rustc_middle/src/ty/list.rs
@@ -1,4 +1,5 @@
use crate::arena::Arena;
+use rustc_data_structures::aligned::{align_of, Aligned};
use rustc_serialize::{Encodable, Encoder};
use std::alloc::Layout;
use std::cmp::Ordering;
@@ -198,22 +199,23 @@ impl<'a, T: Copy> IntoIterator for &'a List<T> {
unsafe impl<T: Sync> Sync for List<T> {}
-unsafe impl<'a, T: 'a> rustc_data_structures::tagged_ptr::Pointer for &'a List<T> {
- const BITS: usize = std::mem::align_of::<usize>().trailing_zeros() as usize;
-
- #[inline]
- fn into_usize(self) -> usize {
- self as *const List<T> as usize
- }
-
- #[inline]
- unsafe fn from_usize(ptr: usize) -> &'a List<T> {
- &*(ptr as *const List<T>)
- }
+// We need this since `List` uses extern type `OpaqueListContents`.
+#[cfg(parallel_compiler)]
+use rustc_data_structures::sync::DynSync;
+#[cfg(parallel_compiler)]
+unsafe impl<T: DynSync> DynSync for List<T> {}
+
+// Safety:
+// Layouts of `Equivalent<T>` and `List<T>` are the same, modulo opaque tail,
+// thus aligns of `Equivalent<T>` and `List<T>` must be the same.
+unsafe impl<T> Aligned for List<T> {
+ const ALIGN: ptr::Alignment = {
+ #[repr(C)]
+ struct Equivalent<T> {
+ _len: usize,
+ _data: [T; 0],
+ }
- unsafe fn with_ref<R, F: FnOnce(&Self) -> R>(ptr: usize, f: F) -> R {
- // `Self` is `&'a List<T>` which impls `Copy`, so this is fine.
- let ptr = Self::from_usize(ptr);
- f(&ptr)
- }
+ align_of::<Equivalent<T>>()
+ };
}
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 2e516f291..a8d0dca37 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -21,6 +21,7 @@ use crate::error::{OpaqueHiddenTypeMismatch, TypeMismatchReason};
use crate::metadata::ModChild;
use crate::middle::privacy::EffectiveVisibilities;
use crate::mir::{Body, GeneratorLayout};
+use crate::query::Providers;
use crate::traits::{self, Reveal};
use crate::ty;
use crate::ty::fast_reject::SimplifiedType;
@@ -36,12 +37,12 @@ use rustc_data_structures::intern::Interned;
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::tagged_ptr::CopyTaggedPtr;
-use rustc_errors::ErrorGuaranteed;
+use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey};
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res};
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap};
use rustc_hir::Node;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_macros::HashStable;
use rustc_query_system::ich::StableHashingContext;
use rustc_serialize::{Decodable, Encodable};
@@ -84,8 +85,7 @@ pub use self::consts::{
Const, ConstData, ConstInt, ConstKind, Expr, InferConst, ScalarInt, UnevaluatedConst, ValTree,
};
pub use self::context::{
- tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, OnDiskCache, TyCtxt,
- TyCtxtFeed,
+ tls, CtxtInterners, DeducedParamAttrs, FreeRegionInfo, GlobalCtxt, Lift, TyCtxt, TyCtxtFeed,
};
pub use self::instance::{Instance, InstanceDef, ShortInstance, UnusedGenericParams};
pub use self::list::List;
@@ -122,7 +122,6 @@ pub mod inhabitedness;
pub mod layout;
pub mod normalize_erasing_regions;
pub mod print;
-pub mod query;
pub mod relate;
pub mod subst;
pub mod trait_def;
@@ -166,8 +165,7 @@ pub struct ResolverGlobalCtxt {
pub effective_visibilities: EffectiveVisibilities,
pub extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
pub maybe_unused_trait_imports: FxIndexSet<LocalDefId>,
- pub module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>,
- pub module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
+ pub module_children: LocalDefIdMap<Vec<ModChild>>,
pub glob_map: FxHashMap<LocalDefId, FxHashSet<Symbol>>,
pub main_def: Option<MainDefinition>,
pub trait_impls: FxIndexMap<DefId, Vec<LocalDefId>>,
@@ -861,6 +859,11 @@ impl<'tcx> PolyTraitPredicate<'tcx> {
pub fn is_const_if_const(self) -> bool {
self.skip_binder().is_const_if_const()
}
+
+ #[inline]
+ pub fn polarity(self) -> ImplPolarity {
+ self.skip_binder().polarity
+ }
}
/// `A: B`
@@ -993,21 +996,15 @@ impl<'tcx> Term<'tcx> {
}
}
- /// This function returns the inner `AliasTy` if this term is a projection.
- ///
- /// FIXME: rename `AliasTy` to `AliasTerm` and make sure we correctly
- /// deal with constants.
- pub fn to_projection_term(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
+ /// This function returns the inner `AliasTy` for a `ty::Alias` or `ConstKind::Unevaluated`.
+ pub fn to_alias_ty(&self, tcx: TyCtxt<'tcx>) -> Option<AliasTy<'tcx>> {
match self.unpack() {
- TermKind::Ty(ty) => match ty.kind() {
- ty::Alias(kind, alias_ty) => match kind {
- AliasKind::Projection => Some(*alias_ty),
- AliasKind::Opaque => None,
- },
+ TermKind::Ty(ty) => match *ty.kind() {
+ ty::Alias(_kind, alias_ty) => Some(alias_ty),
_ => None,
},
TermKind::Const(ct) => match ct.kind() {
- ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def.did, uv.substs)),
+ ConstKind::Unevaluated(uv) => Some(tcx.mk_alias_ty(uv.def, uv.substs)),
_ => None,
},
}
@@ -1067,6 +1064,24 @@ impl ParamTerm {
}
}
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+pub enum TermVid<'tcx> {
+ Ty(ty::TyVid),
+ Const(ty::ConstVid<'tcx>),
+}
+
+impl From<ty::TyVid> for TermVid<'_> {
+ fn from(value: ty::TyVid) -> Self {
+ TermVid::Ty(value)
+ }
+}
+
+impl<'tcx> From<ty::ConstVid<'tcx>> for TermVid<'tcx> {
+ fn from(value: ty::ConstVid<'tcx>) -> Self {
+ TermVid::Const(value)
+ }
+}
+
/// This kind of predicate has no *direct* correspondent in the
/// syntax, but it roughly corresponds to the syntactic forms:
///
@@ -1207,6 +1222,18 @@ impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for Binder<'tcx, TraitRef
}
}
+impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitRef<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
+ ty::Binder::dummy(self).to_predicate(tcx)
+ }
+}
+
+impl<'tcx> ToPredicate<'tcx, PolyTraitPredicate<'tcx>> for TraitPredicate<'tcx> {
+ fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> PolyTraitPredicate<'tcx> {
+ ty::Binder::dummy(self)
+ }
+}
+
impl<'tcx> ToPredicate<'tcx> for PolyTraitPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self.map_bound(|p| PredicateKind::Clause(Clause::Trait(p))).to_predicate(tcx)
@@ -1231,6 +1258,12 @@ impl<'tcx> ToPredicate<'tcx> for PolyProjectionPredicate<'tcx> {
}
}
+impl<'tcx> ToPredicate<'tcx> for TraitPredicate<'tcx> {
+ fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
+ PredicateKind::Clause(Clause::Trait(self)).to_predicate(tcx)
+ }
+}
+
impl<'tcx> Predicate<'tcx> {
pub fn to_opt_poly_trait_pred(self) -> Option<PolyTraitPredicate<'tcx>> {
let predicate = self.kind();
@@ -1400,14 +1433,26 @@ pub struct OpaqueHiddenType<'tcx> {
}
impl<'tcx> OpaqueHiddenType<'tcx> {
- pub fn report_mismatch(&self, other: &Self, tcx: TyCtxt<'tcx>) -> ErrorGuaranteed {
+ pub fn report_mismatch(
+ &self,
+ other: &Self,
+ opaque_def_id: LocalDefId,
+ tcx: TyCtxt<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ if let Some(diag) = tcx
+ .sess
+ .diagnostic()
+ .steal_diagnostic(tcx.def_span(opaque_def_id), StashKey::OpaqueHiddenTypeMismatch)
+ {
+ diag.cancel();
+ }
// Found different concrete types for the opaque type.
let sub_diag = if self.span == other.span {
TypeMismatchReason::ConflictType { span: self.span }
} else {
TypeMismatchReason::PreviousUse { span: self.span }
};
- tcx.sess.emit_err(OpaqueHiddenTypeMismatch {
+ tcx.sess.create_err(OpaqueHiddenTypeMismatch {
self_ty: self.ty,
other_ty: other.ty,
other_span: other.span,
@@ -1471,135 +1516,6 @@ pub struct BoundConst<'tcx> {
pub type PlaceholderConst<'tcx> = Placeholder<BoundVar>;
-/// A `DefId` which, in case it is a const argument, is potentially bundled with
-/// the `DefId` of the generic parameter it instantiates.
-///
-/// This is used to avoid calls to `type_of` for const arguments during typeck
-/// which cause cycle errors.
-///
-/// ```rust
-/// struct A;
-/// impl A {
-/// fn foo<const N: usize>(&self) -> [u8; N] { [0; N] }
-/// // ^ const parameter
-/// }
-/// struct B;
-/// impl B {
-/// fn foo<const M: u8>(&self) -> usize { 42 }
-/// // ^ const parameter
-/// }
-///
-/// fn main() {
-/// let a = A;
-/// let _b = a.foo::<{ 3 + 7 }>();
-/// // ^^^^^^^^^ const argument
-/// }
-/// ```
-///
-/// Let's look at the call `a.foo::<{ 3 + 7 }>()` here. We do not know
-/// which `foo` is used until we know the type of `a`.
-///
-/// We only know the type of `a` once we are inside of `typeck(main)`.
-/// We also end up normalizing the type of `_b` during `typeck(main)` which
-/// requires us to evaluate the const argument.
-///
-/// To evaluate that const argument we need to know its type,
-/// which we would get using `type_of(const_arg)`. This requires us to
-/// resolve `foo` as it can be either `usize` or `u8` in this example.
-/// However, resolving `foo` once again requires `typeck(main)` to get the type of `a`,
-/// which results in a cycle.
-///
-/// In short we must not call `type_of(const_arg)` during `typeck(main)`.
-///
-/// When first creating the `ty::Const` of the const argument inside of `typeck` we have
-/// already resolved `foo` so we know which const parameter this argument instantiates.
-/// This means that we also know the expected result of `type_of(const_arg)` even if we
-/// aren't allowed to call that query: it is equal to `type_of(const_param)` which is
-/// trivial to compute.
-///
-/// If we now want to use that constant in a place which potentially needs its type
-/// we also pass the type of its `const_param`. This is the point of `WithOptConstParam`,
-/// except that instead of a `Ty` we bundle the `DefId` of the const parameter.
-/// Meaning that we need to use `type_of(const_param_did)` if `const_param_did` is `Some`
-/// to get the type of `did`.
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable, Lift, TyEncodable, TyDecodable)]
-#[derive(PartialEq, Eq, PartialOrd, Ord)]
-#[derive(Hash, HashStable)]
-pub struct WithOptConstParam<T> {
- pub did: T,
- /// The `DefId` of the corresponding generic parameter in case `did` is
- /// a const argument.
- ///
- /// Note that even if `did` is a const argument, this may still be `None`.
- /// All queries taking `WithOptConstParam` start by calling `tcx.opt_const_param_of(def.did)`
- /// to potentially update `param_did` in the case it is `None`.
- pub const_param_did: Option<DefId>,
-}
-
-impl<T> WithOptConstParam<T> {
- /// Creates a new `WithOptConstParam` setting `const_param_did` to `None`.
- #[inline(always)]
- pub fn unknown(did: T) -> WithOptConstParam<T> {
- WithOptConstParam { did, const_param_did: None }
- }
-}
-
-impl WithOptConstParam<LocalDefId> {
- /// Returns `Some((did, param_did))` if `def_id` is a const argument,
- /// `None` otherwise.
- #[inline(always)]
- pub fn try_lookup(did: LocalDefId, tcx: TyCtxt<'_>) -> Option<(LocalDefId, DefId)> {
- tcx.opt_const_param_of(did).map(|param_did| (did, param_did))
- }
-
- /// In case `self` is unknown but `self.did` is a const argument, this returns
- /// a `WithOptConstParam` with the correct `const_param_did`.
- #[inline(always)]
- pub fn try_upgrade(self, tcx: TyCtxt<'_>) -> Option<WithOptConstParam<LocalDefId>> {
- if self.const_param_did.is_none() {
- if let const_param_did @ Some(_) = tcx.opt_const_param_of(self.did) {
- return Some(WithOptConstParam { did: self.did, const_param_did });
- }
- }
-
- None
- }
-
- pub fn to_global(self) -> WithOptConstParam<DefId> {
- WithOptConstParam { did: self.did.to_def_id(), const_param_did: self.const_param_did }
- }
-
- pub fn def_id_for_type_of(self) -> DefId {
- if let Some(did) = self.const_param_did { did } else { self.did.to_def_id() }
- }
-}
-
-impl WithOptConstParam<DefId> {
- pub fn as_local(self) -> Option<WithOptConstParam<LocalDefId>> {
- self.did
- .as_local()
- .map(|did| WithOptConstParam { did, const_param_did: self.const_param_did })
- }
-
- pub fn as_const_arg(self) -> Option<(LocalDefId, DefId)> {
- if let Some(param_did) = self.const_param_did {
- if let Some(did) = self.did.as_local() {
- return Some((did, param_did));
- }
- }
-
- None
- }
-
- pub fn is_local(self) -> bool {
- self.did.is_local()
- }
-
- pub fn def_id_for_type_of(self) -> DefId {
- self.const_param_did.unwrap_or(self.did)
- }
-}
-
/// When type checking, we use the `ParamEnv` to track
/// details about the set of where-clauses that are in scope at this
/// particular point.
@@ -1626,27 +1542,12 @@ struct ParamTag {
constness: hir::Constness,
}
-unsafe impl rustc_data_structures::tagged_ptr::Tag for ParamTag {
- const BITS: usize = 2;
- #[inline]
- fn into_usize(self) -> usize {
- match self {
- Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst } => 0,
- Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst } => 1,
- Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const } => 2,
- Self { reveal: traits::Reveal::All, constness: hir::Constness::Const } => 3,
- }
- }
- #[inline]
- unsafe fn from_usize(ptr: usize) -> Self {
- match ptr {
- 0 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
- 1 => Self { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
- 2 => Self { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
- 3 => Self { reveal: traits::Reveal::All, constness: hir::Constness::Const },
- _ => std::hint::unreachable_unchecked(),
- }
- }
+impl_tag! {
+ impl Tag for ParamTag;
+ ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::NotConst },
+ ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::NotConst },
+ ParamTag { reveal: traits::Reveal::UserFacing, constness: hir::Constness::Const },
+ ParamTag { reveal: traits::Reveal::All, constness: hir::Constness::Const },
}
impl<'tcx> fmt::Debug for ParamEnv<'tcx> {
@@ -1850,12 +1751,6 @@ impl<'tcx, T> ParamEnvAnd<'tcx, T> {
pub fn into_parts(self) -> (ParamEnv<'tcx>, T) {
(self.param_env, self.value)
}
-
- #[inline]
- pub fn without_const(mut self) -> Self {
- self.param_env = self.param_env.without_const();
- self
- }
}
#[derive(Copy, Clone, Debug, HashStable, Encodable, Decodable)]
@@ -1868,7 +1763,7 @@ pub struct Destructor {
bitflags! {
#[derive(HashStable, TyEncodable, TyDecodable)]
- pub struct VariantFlags: u32 {
+ pub struct VariantFlags: u8 {
const NO_VARIANT_FLAGS = 0;
/// Indicates whether the field list of this variant is `#[non_exhaustive]`.
const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0;
@@ -1969,6 +1864,16 @@ impl VariantDef {
pub fn ctor_def_id(&self) -> Option<DefId> {
self.ctor.map(|(_, def_id)| def_id)
}
+
+ /// Returns the one field in this variant.
+ ///
+ /// `panic!`s if there are no fields or multiple fields.
+ #[inline]
+ pub fn single_field(&self) -> &FieldDef {
+ assert!(self.fields.len() == 1);
+
+ &self.fields[FieldIdx::from_u32(0)]
+ }
}
impl PartialEq for VariantDef {
@@ -1983,7 +1888,20 @@ impl PartialEq for VariantDef {
let Self { def_id: lhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = &self;
let Self { def_id: rhs_def_id, ctor: _, name: _, discr: _, fields: _, flags: _ } = other;
- lhs_def_id == rhs_def_id
+
+ let res = lhs_def_id == rhs_def_id;
+
+ // Double check that implicit assumption detailed above.
+ if cfg!(debug_assertions) && res {
+ let deep = self.ctor == other.ctor
+ && self.name == other.name
+ && self.discr == other.discr
+ && self.fields == other.fields
+ && self.flags == other.flags;
+ assert!(deep, "VariantDef for the same def-id has differing data");
+ }
+
+ res
}
}
@@ -2038,7 +1956,15 @@ impl PartialEq for FieldDef {
let Self { did: rhs_did, name: _, vis: _ } = other;
- lhs_did == rhs_did
+ let res = lhs_did == rhs_did;
+
+ // Double check that implicit assumption detailed above.
+ if cfg!(debug_assertions) && res {
+ let deep = self.name == other.name && self.vis == other.vis;
+ assert!(deep, "FieldDef for the same def-id has differing data");
+ }
+
+ res
}
}
@@ -2245,10 +2171,9 @@ impl<'tcx> TyCtxt<'tcx> {
/// See [`item_name`][Self::item_name] for more information.
pub fn opt_item_ident(self, def_id: DefId) -> Option<Ident> {
let def = self.opt_item_name(def_id)?;
- let span = def_id
- .as_local()
- .and_then(|id| self.def_ident_span(id))
- .unwrap_or(rustc_span::DUMMY_SP);
+ let span = self
+ .def_ident_span(def_id)
+ .unwrap_or_else(|| bug!("missing ident span for {def_id:?}"));
Some(Ident::new(def, span))
}
@@ -2289,8 +2214,8 @@ impl<'tcx> TyCtxt<'tcx> {
let impl_trait_ref2 = self.impl_trait_ref(def_id2);
// If either trait impl references an error, they're allowed to overlap,
// as one of them essentially doesn't exist.
- if impl_trait_ref1.map_or(false, |tr| tr.subst_identity().references_error())
- || impl_trait_ref2.map_or(false, |tr| tr.subst_identity().references_error())
+ if impl_trait_ref1.is_some_and(|tr| tr.subst_identity().references_error())
+ || impl_trait_ref2.is_some_and(|tr| tr.subst_identity().references_error())
{
return Some(ImplOverlapKind::Permitted { marker: false });
}
@@ -2311,7 +2236,7 @@ impl<'tcx> TyCtxt<'tcx> {
let is_marker_overlap = {
let is_marker_impl = |trait_ref: Option<EarlyBinder<TraitRef<'_>>>| -> bool {
- trait_ref.map_or(false, |tr| self.trait_def(tr.skip_binder().def_id).is_marker)
+ trait_ref.is_some_and(|tr| self.trait_def(tr.skip_binder().def_id).is_marker)
};
is_marker_impl(impl_trait_ref1) && is_marker_impl(impl_trait_ref2)
};
@@ -2361,7 +2286,7 @@ impl<'tcx> TyCtxt<'tcx> {
match instance {
ty::InstanceDef::Item(def) => {
debug!("calling def_kind on def: {:?}", def);
- let def_kind = self.def_kind(def.did);
+ let def_kind = self.def_kind(def);
debug!("returned from def_kind: {:?}", def_kind);
match def_kind {
DefKind::Const
@@ -2369,13 +2294,10 @@ impl<'tcx> TyCtxt<'tcx> {
| DefKind::AssocConst
| DefKind::Ctor(..)
| DefKind::AnonConst
- | DefKind::InlineConst => self.mir_for_ctfe_opt_const_arg(def),
+ | DefKind::InlineConst => self.mir_for_ctfe(def),
// If the caller wants `mir_for_ctfe` of a function they should not be using
// `instance_mir`, so we'll assume const fn also wants the optimized version.
- _ => {
- assert_eq!(def.const_param_did, None);
- self.optimized_mir(def.did)
- }
+ _ => self.optimized_mir(def),
}
}
ty::InstanceDef::VTableShim(..)
@@ -2566,9 +2488,7 @@ impl<'tcx> TyCtxt<'tcx> {
&& if self.features().collapse_debuginfo {
span.in_macro_expansion_with_collapse_debuginfo()
} else {
- // Inlined spans should not be collapsed as that leads to all of the
- // inlined code being attributed to the inline callsite.
- span.from_expansion() && !span.is_inlined()
+ span.from_expansion()
}
}
@@ -2599,6 +2519,18 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
+ /// Returns the `DefId` of the item within which the `impl Trait` is declared.
+ /// For type-alias-impl-trait this is the `type` alias.
+ /// For impl-trait-in-assoc-type this is the assoc type.
+ /// For return-position-impl-trait this is the function.
+ pub fn impl_trait_parent(self, mut def_id: LocalDefId) -> LocalDefId {
+ // Find the surrounding item (type alias or assoc type)
+ while let DefKind::OpaqueTy = self.def_kind(def_id) {
+ def_id = self.local_parent(def_id);
+ }
+ def_id
+ }
+
pub fn impl_method_has_trait_impl_trait_tys(self, def_id: DefId) -> bool {
if self.def_kind(def_id) != DefKind::AssocFn {
return false;
@@ -2643,7 +2575,7 @@ pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option<LocalDefId>
hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => {
Some(parent)
}
- hir::OpaqueTyOrigin::TyAlias => None,
+ hir::OpaqueTyOrigin::TyAlias { .. } => None,
};
}
}
@@ -2701,7 +2633,7 @@ pub fn ast_uint_ty(uty: UintTy) -> ast::UintTy {
}
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
closure::provide(providers);
context::provide(providers);
erase_regions::provide(providers);
@@ -2710,7 +2642,7 @@ pub fn provide(providers: &mut ty::query::Providers) {
print::provide(providers);
super::util::bug::provide(providers);
super::middle::provide(providers);
- *providers = ty::query::Providers {
+ *providers = Providers {
trait_impls_of: trait_def::trait_impls_of_provider,
incoherent_impls: trait_def::incoherent_impls_provider,
const_param_default: consts::const_param_default,
diff --git a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
index 7c59879a1..a0c8d299f 100644
--- a/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
+++ b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs
@@ -32,7 +32,7 @@ impl<'tcx> TyCtxt<'tcx> {
///
/// This should only be used outside of type inference. For example,
/// it assumes that normalization will succeed.
- #[tracing::instrument(level = "debug", skip(self, param_env))]
+ #[tracing::instrument(level = "debug", skip(self, param_env), ret)]
pub fn normalize_erasing_regions<T>(self, param_env: ty::ParamEnv<'tcx>, value: T) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
@@ -139,7 +139,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
param_substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- value: T,
+ value: EarlyBinder<T>,
) -> T
where
T: TypeFoldable<TyCtxt<'tcx>>,
@@ -151,7 +151,7 @@ impl<'tcx> TyCtxt<'tcx> {
param_env={:?})",
param_substs, value, param_env,
);
- let substituted = EarlyBinder(value).subst(self, param_substs);
+ let substituted = value.subst(self, param_substs);
self.normalize_erasing_regions(param_env, substituted)
}
@@ -163,7 +163,7 @@ impl<'tcx> TyCtxt<'tcx> {
self,
param_substs: SubstsRef<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- value: T,
+ value: EarlyBinder<T>,
) -> Result<T, NormalizationError<'tcx>>
where
T: TypeFoldable<TyCtxt<'tcx>>,
@@ -175,7 +175,7 @@ impl<'tcx> TyCtxt<'tcx> {
param_env={:?})",
param_substs, value, param_env,
);
- let substituted = EarlyBinder(value).subst(self, param_substs);
+ let substituted = value.subst(self, param_substs);
self.try_normalize_erasing_regions(param_env, substituted)
}
}
diff --git a/compiler/rustc_middle/src/ty/opaque_types.rs b/compiler/rustc_middle/src/ty/opaque_types.rs
index 751f3066c..1b336b7bf 100644
--- a/compiler/rustc_middle/src/ty/opaque_types.rs
+++ b/compiler/rustc_middle/src/ty/opaque_types.rs
@@ -177,7 +177,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
.sess
.struct_span_err(
self.span,
- &format!(
+ format!(
"type parameter `{}` is part of concrete type but not \
used in parameter list for the `impl Trait` type alias",
ty
@@ -207,14 +207,16 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ReverseMapper<'tcx> {
Some(GenericArgKind::Const(c1)) => c1,
Some(u) => panic!("const mapped to unexpected kind: {:?}", u),
None => {
- if !self.ignore_errors {
- self.tcx.sess.emit_err(ConstNotUsedTraitAlias {
+ let guar = self
+ .tcx
+ .sess
+ .create_err(ConstNotUsedTraitAlias {
ct: ct.to_string(),
span: self.span,
- });
- }
+ })
+ .emit_unless(self.ignore_errors);
- self.interner().const_error(ct.ty())
+ self.interner().const_error(ct.ty(), guar)
}
}
}
diff --git a/compiler/rustc_middle/src/ty/parameterized.rs b/compiler/rustc_middle/src/ty/parameterized.rs
index 7534d06ae..a2e77d9cd 100644
--- a/compiler/rustc_middle/src/ty/parameterized.rs
+++ b/compiler/rustc_middle/src/ty/parameterized.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefIndex;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use crate::ty;
@@ -56,6 +56,7 @@ trivially_parameterized_over_tcx! {
std::string::String,
crate::metadata::ModChild,
crate::middle::codegen_fn_attrs::CodegenFnAttrs,
+ crate::middle::debugger_visualizer::DebuggerVisualizerFile,
crate::middle::exported_symbols::SymbolExportInfo,
crate::middle::resolve_bound_vars::ObjectLifetimeDefault,
crate::mir::ConstQualifs,
@@ -91,7 +92,6 @@ trivially_parameterized_over_tcx! {
rustc_session::cstore::ForeignModule,
rustc_session::cstore::LinkagePreference,
rustc_session::cstore::NativeLib,
- rustc_span::DebuggerVisualizerFile,
rustc_span::ExpnData,
rustc_span::ExpnHash,
rustc_span::ExpnId,
diff --git a/compiler/rustc_middle/src/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs
index d947d9604..64e7480e6 100644
--- a/compiler/rustc_middle/src/ty/print/mod.rs
+++ b/compiler/rustc_middle/src/ty/print/mod.rs
@@ -169,8 +169,11 @@ pub trait Printer<'tcx>: Sized {
self.path_append(
|cx: Self| {
if trait_qualify_parent {
- let trait_ref =
- cx.tcx().mk_trait_ref(parent_def_id, parent_substs.iter().copied());
+ let trait_ref = ty::TraitRef::new(
+ cx.tcx(),
+ parent_def_id,
+ parent_substs.iter().copied(),
+ );
cx.path_qualified(trait_ref.self_ty(), Some(trait_ref))
} else {
cx.print_def_path(parent_def_id, parent_substs)
@@ -327,6 +330,6 @@ pub fn describe_as_module(def_id: LocalDefId, tcx: TyCtxt<'_>) -> String {
if def_id.is_top_level_module() {
"top-level module".to_string()
} else {
- format!("module `{}`", tcx.def_path_str(def_id.to_def_id()))
+ format!("module `{}`", tcx.def_path_str(def_id))
}
}
diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs
index 72caadaf6..d6c88ea96 100644
--- a/compiler/rustc_middle/src/ty/print/pretty.rs
+++ b/compiler/rustc_middle/src/ty/print/pretty.rs
@@ -1,4 +1,6 @@
use crate::mir::interpret::{AllocRange, GlobalAlloc, Pointer, Provenance, Scalar};
+use crate::query::IntoQueryParam;
+use crate::query::Providers;
use crate::ty::{
self, ConstInt, ParamConst, ScalarInt, Term, TermKind, Ty, TyCtxt, TypeFoldable,
TypeSuperFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
@@ -698,10 +700,10 @@ pub trait PrettyPrinter<'tcx>:
if verbose { p!(write("{:?}", infer_ty)) } else { p!(write("{}", infer_ty)) }
}
}
- ty::Error(_) => p!("[type error]"),
+ ty::Error(_) => p!("{{type error}}"),
ty::Param(ref param_ty) => p!(print(param_ty)),
ty::Bound(debruijn, bound_ty) => match bound_ty.kind {
- ty::BoundTyKind::Anon => self.pretty_print_bound_var(debruijn, bound_ty.var)?,
+ ty::BoundTyKind::Anon => debug_bound_var(&mut self, debruijn, bound_ty.var)?,
ty::BoundTyKind::Param(_, s) => match self.should_print_verbose() {
true if debruijn == ty::INNERMOST => p!(write("^{}", s)),
true => p!(write("^{}_{}", debruijn.index(), s)),
@@ -728,7 +730,7 @@ pub trait PrettyPrinter<'tcx>:
ty::Foreign(def_id) => {
p!(print_def_path(def_id, &[]));
}
- ty::Alias(ty::Projection, ref data) => {
+ ty::Alias(ty::Projection | ty::Inherent, ref data) => {
if !(self.should_print_verbose() || NO_QUERIES.with(|q| q.get()))
&& self.tcx().is_impl_trait_in_trait(data.def_id)
{
@@ -738,7 +740,9 @@ pub trait PrettyPrinter<'tcx>:
}
}
ty::Placeholder(placeholder) => match placeholder.bound.kind {
- ty::BoundTyKind::Anon => p!(write("Placeholder({:?})", placeholder)),
+ ty::BoundTyKind::Anon => {
+ debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound.var)?;
+ }
ty::BoundTyKind::Param(_, name) => p!(write("{}", name)),
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
@@ -911,7 +915,7 @@ pub trait PrettyPrinter<'tcx>:
// Grab the "TraitA + TraitB" from `impl TraitA + TraitB`,
// by looking up the projections associated with the def_id.
- let bounds = tcx.bound_explicit_item_bounds(def_id);
+ let bounds = tcx.explicit_item_bounds(def_id);
let mut traits = FxIndexMap::default();
let mut fn_traits = FxIndexMap::default();
@@ -1160,16 +1164,20 @@ pub trait PrettyPrinter<'tcx>:
traits.entry(trait_ref).or_default().extend(proj_ty);
}
- fn pretty_print_bound_var(
- &mut self,
- debruijn: ty::DebruijnIndex,
- var: ty::BoundVar,
- ) -> Result<(), Self::Error> {
- if debruijn == ty::INNERMOST {
- write!(self, "^{}", var.index())
- } else {
- write!(self, "^{}_{}", debruijn.index(), var.index())
- }
+ fn pretty_print_inherent_projection(
+ self,
+ alias_ty: &ty::AliasTy<'tcx>,
+ ) -> Result<Self::Path, Self::Error> {
+ let def_key = self.tcx().def_key(alias_ty.def_id);
+ self.path_generic_args(
+ |cx| {
+ cx.path_append(
+ |cx| cx.path_qualified(alias_ty.self_ty(), None),
+ &def_key.disambiguated_data,
+ )
+ },
+ &alias_ty.substs[1..],
+ )
}
fn ty_infer_name(&self, _: ty::TyVid) -> Option<Symbol> {
@@ -1305,7 +1313,7 @@ pub trait PrettyPrinter<'tcx>:
define_scoped_cx!(self);
if self.should_print_verbose() {
- p!(write("Const({:?}: {:?})", ct.kind(), ct.ty()));
+ p!(write("{:?}", ct));
return Ok(self);
}
@@ -1328,13 +1336,13 @@ pub trait PrettyPrinter<'tcx>:
match ct.kind() {
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs }) => {
- match self.tcx().def_kind(def.did) {
+ match self.tcx().def_kind(def) {
DefKind::Const | DefKind::AssocConst => {
- p!(print_value_path(def.did, substs))
+ p!(print_value_path(def, substs))
}
DefKind::AnonConst => {
if def.is_local()
- && let span = self.tcx().def_span(def.did)
+ && let span = self.tcx().def_span(def)
&& let Ok(snip) = self.tcx().sess.source_map().span_to_snippet(span)
{
p!(write("{}", snip))
@@ -1344,7 +1352,7 @@ pub trait PrettyPrinter<'tcx>:
// cause printing to enter an infinite recursion if the anon const is in the self type i.e.
// `impl<T: Default> Default for [T; 32 - 1 - 1 - 1] {`
// where we would try to print `<[T; /* print `constant#0` again */] as Default>::{constant#0}`
- p!(write("{}::{}", self.tcx().crate_name(def.did.krate), self.tcx().def_path(def.did).to_string_no_crate_verbose()))
+ p!(write("{}::{}", self.tcx().crate_name(def.krate), self.tcx().def_path(def).to_string_no_crate_verbose()))
}
}
defkind => bug!("`{:?}` has unexpected defkind {:?}", ct, defkind),
@@ -1364,13 +1372,15 @@ pub trait PrettyPrinter<'tcx>:
}
ty::ConstKind::Bound(debruijn, bound_var) => {
- self.pretty_print_bound_var(debruijn, bound_var)?
+ debug_bound_var(&mut self, debruijn, bound_var)?
}
- ty::ConstKind::Placeholder(placeholder) => p!(write("Placeholder({:?})", placeholder)),
+ ty::ConstKind::Placeholder(placeholder) => {
+ debug_placeholder_var(&mut self, placeholder.universe, placeholder.bound)?;
+ },
// FIXME(generic_const_exprs):
// write out some legible representation of an abstract const?
- ty::ConstKind::Expr(_) => p!("[const expr]"),
- ty::ConstKind::Error(_) => p!("[const error]"),
+ ty::ConstKind::Expr(_) => p!("{{const expr}}"),
+ ty::ConstKind::Error(_) => p!("{{const error}}"),
};
Ok(self)
}
@@ -1787,17 +1797,27 @@ fn guess_def_namespace(tcx: TyCtxt<'_>, def_id: DefId) -> Namespace {
impl<'t> TyCtxt<'t> {
/// Returns a string identifying this `DefId`. This string is
/// suitable for user output.
- pub fn def_path_str(self, def_id: DefId) -> String {
+ pub fn def_path_str(self, def_id: impl IntoQueryParam<DefId>) -> String {
self.def_path_str_with_substs(def_id, &[])
}
- pub fn def_path_str_with_substs(self, def_id: DefId, substs: &'t [GenericArg<'t>]) -> String {
+ pub fn def_path_str_with_substs(
+ self,
+ def_id: impl IntoQueryParam<DefId>,
+ substs: &'t [GenericArg<'t>],
+ ) -> String {
+ let def_id = def_id.into_query_param();
let ns = guess_def_namespace(self, def_id);
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 {
+ pub fn value_path_str_with_substs(
+ self,
+ def_id: impl IntoQueryParam<DefId>,
+ substs: &'t [GenericArg<'t>],
+ ) -> String {
+ let def_id = def_id.into_query_param();
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()
@@ -2518,7 +2538,7 @@ impl<'tcx> FmtPrinter<'_, 'tcx> {
self.used_region_names.insert(name);
}
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
// We collect types in order to prevent really large types from compiling for
@@ -2608,6 +2628,12 @@ macro_rules! define_print_and_forward_display {
#[derive(Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
pub struct TraitRefPrintOnlyTraitPath<'tcx>(ty::TraitRef<'tcx>);
+impl<'tcx> rustc_errors::IntoDiagnosticArg for TraitRefPrintOnlyTraitPath<'tcx> {
+ fn into_diagnostic_arg(self) -> rustc_errors::DiagnosticArgValue<'static> {
+ self.to_string().into_diagnostic_arg()
+ }
+}
+
impl<'tcx> fmt::Debug for TraitRefPrintOnlyTraitPath<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
fmt::Display::fmt(self, f)
@@ -2665,7 +2691,7 @@ impl<'tcx> ty::PolyTraitPredicate<'tcx> {
}
}
-#[derive(Debug, Copy, Clone, TypeFoldable, TypeVisitable, Lift)]
+#[derive(Debug, Copy, Clone, Lift)]
pub struct PrintClosureAsImpl<'tcx> {
pub closure: ty::ClosureSubsts<'tcx>,
}
@@ -2791,6 +2817,9 @@ define_print_and_forward_display! {
if let ty::BoundConstness::ConstIfConst = self.constness && cx.tcx().features().const_trait_impl {
p!("~const ");
}
+ if let ty::ImplPolarity::Negative = self.polarity {
+ p!("!");
+ }
p!(print(self.trait_ref.print_only_trait_path()))
}
@@ -2808,7 +2837,11 @@ define_print_and_forward_display! {
}
ty::AliasTy<'tcx> {
- p!(print_def_path(self.def_id, self.substs));
+ if let DefKind::Impl { of_trait: false } = cx.tcx().def_kind(cx.tcx().parent(self.def_id)) {
+ p!(pretty_print_inherent_projection(self))
+ } else {
+ p!(print_def_path(self.def_id, self.substs));
+ }
}
ty::ClosureKind {
@@ -3020,8 +3053,8 @@ fn trimmed_def_paths(tcx: TyCtxt<'_>, (): ()) -> FxHashMap<DefId, Symbol> {
map
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { trimmed_def_paths, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { trimmed_def_paths, ..*providers };
}
#[derive(Default)]
@@ -3032,3 +3065,27 @@ pub struct OpaqueFnEntry<'tcx> {
fn_trait_ref: Option<ty::PolyTraitRef<'tcx>>,
return_ty: Option<ty::Binder<'tcx, Term<'tcx>>>,
}
+
+pub fn debug_bound_var<T: std::fmt::Write>(
+ fmt: &mut T,
+ debruijn: ty::DebruijnIndex,
+ var: ty::BoundVar,
+) -> Result<(), std::fmt::Error> {
+ if debruijn == ty::INNERMOST {
+ write!(fmt, "^{}", var.index())
+ } else {
+ write!(fmt, "^{}_{}", debruijn.index(), var.index())
+ }
+}
+
+pub fn debug_placeholder_var<T: std::fmt::Write>(
+ fmt: &mut T,
+ universe: ty::UniverseIndex,
+ bound: ty::BoundVar,
+) -> Result<(), std::fmt::Error> {
+ if universe == ty::UniverseIndex::ROOT {
+ write!(fmt, "!{}", bound.index())
+ } else {
+ write!(fmt, "!{}_{}", universe.index(), bound.index())
+ }
+}
diff --git a/compiler/rustc_middle/src/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs
index 46c931d61..3bbe6a23b 100644
--- a/compiler/rustc_middle/src/ty/relate.rs
+++ b/compiler/rustc_middle/src/ty/relate.rs
@@ -7,7 +7,7 @@
use crate::ty::error::{ExpectedFound, TypeError};
use crate::ty::{self, Expr, ImplSubject, Term, TermKind, Ty, TyCtxt, TypeFoldable};
use crate::ty::{GenericArg, GenericArgKind, SubstsRef};
-use rustc_hir as ast;
+use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_target::spec::abi;
use std::iter;
@@ -123,8 +123,8 @@ pub fn relate_type_and_mut<'tcx, R: TypeRelation<'tcx>>(
} else {
let mutbl = a.mutbl;
let (variance, info) = match mutbl {
- ast::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
- ast::Mutability::Mut => {
+ hir::Mutability::Not => (ty::Covariant, ty::VarianceDiagInfo::None),
+ hir::Mutability::Mut => {
(ty::Invariant, ty::VarianceDiagInfo::Invariant { ty: base_ty, param_index: 0 })
}
};
@@ -239,12 +239,12 @@ impl<'tcx> Relate<'tcx> for ty::BoundConstness {
}
}
-impl<'tcx> Relate<'tcx> for ast::Unsafety {
+impl<'tcx> Relate<'tcx> for hir::Unsafety {
fn relate<R: TypeRelation<'tcx>>(
relation: &mut R,
- a: ast::Unsafety,
- b: ast::Unsafety,
- ) -> RelateResult<'tcx, ast::Unsafety> {
+ a: hir::Unsafety,
+ b: hir::Unsafety,
+ ) -> RelateResult<'tcx, hir::Unsafety> {
if a != b {
Err(TypeError::UnsafetyMismatch(expected_found(relation, a, b)))
} else {
@@ -315,7 +315,7 @@ impl<'tcx> Relate<'tcx> for ty::TraitRef<'tcx> {
Err(TypeError::Traits(expected_found(relation, a.def_id, b.def_id)))
} else {
let substs = relate_substs(relation, a.substs, b.substs)?;
- Ok(relation.tcx().mk_trait_ref(a.def_id, substs))
+ Ok(ty::TraitRef::new(relation.tcx(), a.def_id, substs))
}
}
}
@@ -388,24 +388,24 @@ impl<'tcx> Relate<'tcx> for Ty<'tcx> {
}
}
-/// The main "type relation" routine. Note that this does not handle
-/// inference artifacts, so you should filter those out before calling
-/// it.
-pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
+/// Relates `a` and `b` structurally, calling the relation for all nested values.
+/// Any semantic equality, e.g. of projections, and inference variables have to be
+/// handled by the caller.
+pub fn structurally_relate_tys<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
a: Ty<'tcx>,
b: Ty<'tcx>,
) -> RelateResult<'tcx, Ty<'tcx>> {
let tcx = relation.tcx();
- debug!("super_relate_tys: a={:?} b={:?}", a, b);
+ debug!("structurally_relate_tys: a={:?} b={:?}", a, b);
match (a.kind(), b.kind()) {
(&ty::Infer(_), _) | (_, &ty::Infer(_)) => {
// The caller should handle these cases!
- bug!("var types encountered in super_relate_tys")
+ bug!("var types encountered in structurally_relate_tys")
}
(ty::Bound(..), _) | (_, ty::Bound(..)) => {
- bug!("bound types encountered in super_relate_tys")
+ bug!("bound types encountered in structurally_relate_tys")
}
(&ty::Error(guar), _) | (_, &ty::Error(guar)) => Ok(tcx.ty_error(guar)),
@@ -550,6 +550,11 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
Ok(tcx.mk_projection(projection_ty.def_id, projection_ty.substs))
}
+ (&ty::Alias(ty::Inherent, a_data), &ty::Alias(ty::Inherent, b_data)) => {
+ let alias_ty = relation.relate(a_data, b_data)?;
+ Ok(tcx.mk_alias(ty::Inherent, tcx.mk_alias_ty(alias_ty.def_id, alias_ty.substs)))
+ }
+
(
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: a_def_id, substs: a_substs, .. }),
&ty::Alias(ty::Opaque, ty::AliasTy { def_id: b_def_id, substs: b_substs, .. }),
@@ -570,15 +575,18 @@ pub fn super_relate_tys<'tcx, R: TypeRelation<'tcx>>(
}
}
-/// The main "const relation" routine. Note that this does not handle
-/// inference artifacts, so you should filter those out before calling
-/// it.
-pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
+/// Relates `a` and `b` structurally, calling the relation for all nested values.
+/// Any semantic equality, e.g. of unevaluated consts, and inference variables have
+/// to be handled by the caller.
+///
+/// FIXME: This is not totally structual, which probably should be fixed.
+/// See the HACKs below.
+pub fn structurally_relate_consts<'tcx, R: TypeRelation<'tcx>>(
relation: &mut R,
mut a: ty::Const<'tcx>,
mut b: ty::Const<'tcx>,
) -> RelateResult<'tcx, ty::Const<'tcx>> {
- debug!("{}.super_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
+ debug!("{}.structurally_relate_consts(a = {:?}, b = {:?})", relation.tag(), a, b);
let tcx = relation.tcx();
// HACK(const_generics): We still need to eagerly evaluate consts when
@@ -597,7 +605,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
b = tcx.expand_abstract_consts(b);
}
- debug!("{}.super_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
+ debug!("{}.structurally_relate_consts(normed_a = {:?}, normed_b = {:?})", relation.tag(), a, b);
// Currently, the values that can be unified are primitive types,
// and those that derive both `PartialEq` and `Eq`, corresponding
@@ -605,7 +613,7 @@ pub fn super_relate_consts<'tcx, R: TypeRelation<'tcx>>(
let is_match = match (a.kind(), b.kind()) {
(ty::ConstKind::Infer(_), _) | (_, ty::ConstKind::Infer(_)) => {
// The caller should handle these cases!
- bug!("var types encountered in super_relate_consts: {:?} {:?}", a, b)
+ bug!("var types encountered in structurally_relate_consts: {:?} {:?}", a, b)
}
(ty::ConstKind::Error(_), _) => return Ok(a),
diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs
index 5c604bb6d..16cb6c910 100644
--- a/compiler/rustc_middle/src/ty/structural_impls.rs
+++ b/compiler/rustc_middle/src/ty/structural_impls.rs
@@ -4,13 +4,12 @@
//! to help with the tedium.
use crate::mir::interpret;
-use crate::mir::ProjectionKind;
use crate::ty::fold::{FallibleTypeFolder, TypeFoldable, TypeSuperFoldable};
use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer};
use crate::ty::visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
use crate::ty::{self, AliasTy, InferConst, Lift, Term, TermKind, Ty, TyCtxt};
use rustc_hir::def::Namespace;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_target::abi::TyAndLayout;
use std::fmt;
@@ -95,7 +94,7 @@ impl<'tcx> fmt::Debug for ty::FnSig<'tcx> {
impl<'tcx> fmt::Debug for ty::ConstVid<'tcx> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}c", self.index)
+ write!(f, "?{}c", self.index)
}
}
@@ -193,11 +192,49 @@ impl<'tcx> fmt::Debug for AliasTy<'tcx> {
}
}
+impl<'tcx> fmt::Debug for ty::InferConst<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ match self {
+ InferConst::Var(var) => write!(f, "{var:?}"),
+ InferConst::Fresh(var) => write!(f, "Fresh({var:?})"),
+ }
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::Const<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ // This reflects what `Const` looked liked before `Interned` was
+ // introduced. We print it like this to avoid having to update expected
+ // output in a lot of tests.
+ write!(f, "Const {{ ty: {:?}, kind: {:?} }}", self.ty(), self.kind())
+ }
+}
+
+impl<'tcx> fmt::Debug for ty::ConstKind<'tcx> {
+ fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
+ use ty::ConstKind::*;
+ match self {
+ Param(param) => write!(f, "{param:?}"),
+ Infer(var) => write!(f, "{var:?}"),
+ Bound(debruijn, var) => ty::print::debug_bound_var(f, *debruijn, *var),
+ Placeholder(placeholder) => {
+ ty::print::debug_placeholder_var(f, placeholder.universe, placeholder.bound)
+ }
+ Unevaluated(uv) => {
+ f.debug_tuple("Unevaluated").field(&uv.substs).field(&uv.def).finish()
+ }
+ Value(valtree) => write!(f, "{valtree:?}"),
+ Error(_) => write!(f, "[const error]"),
+ Expr(expr) => write!(f, "{expr:?}"),
+ }
+ }
+}
+
///////////////////////////////////////////////////////////////////////////
// Atomic structs
//
// For things that don't carry any arena-allocated data (and are
-// copy...), just add them to one of these lists as appropriat.
+// copy...), just add them to one of these lists as appropriate.
// For things for which the type library provides traversal implementations
// for all Interners, we only need to provide a Lift implementation:
@@ -205,6 +242,7 @@ CloneLiftImpls! {
(),
bool,
usize,
+ u8,
u16,
u32,
u64,
@@ -276,9 +314,7 @@ TrivialTypeTraversalAndLiftImpls! {
}
TrivialTypeTraversalAndLiftImpls! {
- for<'tcx> {
- ty::ValTree<'tcx>,
- }
+ ty::ValTree<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
@@ -375,16 +411,6 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> {
///////////////////////////////////////////////////////////////////////////
// Traversal implementations.
-/// AdtDefs are basically the same as a DefId.
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- _folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(self)
- }
-}
-
impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::AdtDef<'tcx> {
fn visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
&self,
@@ -447,15 +473,6 @@ impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ty::Const<'tcx>> {
}
}
-impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for &'tcx ty::List<ProjectionKind> {
- fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- folder: &mut F,
- ) -> Result<Self, F::Error> {
- ty::util::fold_list(self, folder, |tcx, v| tcx.mk_projs(v))
- }
-}
-
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for Ty<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
@@ -583,24 +600,6 @@ impl<'tcx> TypeVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> {
}
}
-impl<'tcx> TypeSuperFoldable<TyCtxt<'tcx>> for ty::Region<'tcx> {
- fn try_super_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
- self,
- _folder: &mut F,
- ) -> Result<Self, F::Error> {
- Ok(self)
- }
-}
-
-impl<'tcx> TypeSuperVisitable<TyCtxt<'tcx>> for ty::Region<'tcx> {
- fn super_visit_with<V: TypeVisitor<TyCtxt<'tcx>>>(
- &self,
- _visitor: &mut V,
- ) -> ControlFlow<V::BreakTy> {
- ControlFlow::Continue(())
- }
-}
-
impl<'tcx> TypeFoldable<TyCtxt<'tcx>> for ty::Predicate<'tcx> {
fn try_fold_with<F: FallibleTypeFolder<TyCtxt<'tcx>>>(
self,
diff --git a/compiler/rustc_middle/src/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs
index 96c1577d5..e6d51c4ec 100644
--- a/compiler/rustc_middle/src/ty/sty.rs
+++ b/compiler/rustc_middle/src/ty/sty.rs
@@ -19,7 +19,7 @@ use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::LangItem;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_macros::HashStable;
use rustc_span::symbol::{kw, sym, Symbol};
use rustc_span::Span;
@@ -631,7 +631,7 @@ impl<'tcx> UpvarSubsts<'tcx> {
/// type of the constant. The reason that `R` is represented as an extra type parameter
/// is the same reason that [`ClosureSubsts`] have `CS` and `U` as type parameters:
/// inline const can reference lifetimes that are internal to the creating function.
-#[derive(Copy, Clone, Debug, TypeFoldable, TypeVisitable)]
+#[derive(Copy, Clone, Debug)]
pub struct InlineConstSubsts<'tcx> {
/// Generic parameters from the enclosing item,
/// concatenated with the inferred type of the constant.
@@ -727,13 +727,13 @@ impl<'tcx> PolyExistentialPredicate<'tcx> {
ExistentialPredicate::AutoTrait(did) => {
let generics = tcx.generics_of(did);
let trait_ref = if generics.params.len() == 1 {
- tcx.mk_trait_ref(did, [self_ty])
+ ty::TraitRef::new(tcx, did, [self_ty])
} else {
// If this is an ill-formed auto trait, then synthesize
// new error substs for the missing generics.
let err_substs =
ty::InternalSubsts::extend_with_error(tcx, did, &[self_ty.into()]);
- tcx.mk_trait_ref(did, err_substs)
+ ty::TraitRef::new(tcx, did, err_substs)
};
self.rebind(trait_ref).without_const().to_predicate(tcx)
}
@@ -820,36 +820,68 @@ pub struct TraitRef<'tcx> {
pub def_id: DefId,
pub substs: SubstsRef<'tcx>,
/// This field exists to prevent the creation of `TraitRef` without
- /// calling [TyCtxt::mk_trait_ref].
- pub(super) _use_mk_trait_ref_instead: (),
+ /// calling [`TraitRef::new`].
+ pub(super) _use_trait_ref_new_instead: (),
}
impl<'tcx> TraitRef<'tcx> {
+ pub fn new(
+ tcx: TyCtxt<'tcx>,
+ trait_def_id: DefId,
+ substs: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
+ ) -> Self {
+ let substs = tcx.check_and_mk_substs(trait_def_id, substs);
+ Self { def_id: trait_def_id, substs, _use_trait_ref_new_instead: () }
+ }
+
+ pub fn from_lang_item(
+ tcx: TyCtxt<'tcx>,
+ trait_lang_item: LangItem,
+ span: Span,
+ substs: impl IntoIterator<Item: Into<ty::GenericArg<'tcx>>>,
+ ) -> Self {
+ let trait_def_id = tcx.require_lang_item(trait_lang_item, Some(span));
+ Self::new(tcx, trait_def_id, substs)
+ }
+
+ pub fn from_method(
+ tcx: TyCtxt<'tcx>,
+ trait_id: DefId,
+ substs: SubstsRef<'tcx>,
+ ) -> ty::TraitRef<'tcx> {
+ let defs = tcx.generics_of(trait_id);
+ ty::TraitRef::new(tcx, trait_id, tcx.mk_substs(&substs[..defs.params.len()]))
+ }
+
+ /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
+ /// are the parameters defined on trait.
+ pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> TraitRef<'tcx> {
+ ty::TraitRef::new(tcx, def_id, InternalSubsts::identity_for_item(tcx, def_id))
+ }
+
pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
- tcx.mk_trait_ref(
+ ty::TraitRef::new(
+ tcx,
self.def_id,
[self_ty.into()].into_iter().chain(self.substs.iter().skip(1)),
)
}
- /// Returns a `TraitRef` of the form `P0: Foo<P1..Pn>` where `Pi`
- /// are the parameters defined on trait.
- pub fn identity(tcx: TyCtxt<'tcx>, def_id: DefId) -> Binder<'tcx, TraitRef<'tcx>> {
- ty::Binder::dummy(tcx.mk_trait_ref(def_id, InternalSubsts::identity_for_item(tcx, def_id)))
+ /// Converts this trait ref to a trait predicate with a given `constness` and a positive polarity.
+ #[inline]
+ pub fn with_constness(self, constness: ty::BoundConstness) -> ty::TraitPredicate<'tcx> {
+ ty::TraitPredicate { trait_ref: self, constness, polarity: ty::ImplPolarity::Positive }
}
+ /// Converts this trait ref to a trait predicate without `const` and a positive polarity.
#[inline]
- pub fn self_ty(&self) -> Ty<'tcx> {
- self.substs.type_at(0)
+ pub fn without_const(self) -> ty::TraitPredicate<'tcx> {
+ self.with_constness(ty::BoundConstness::NotConst)
}
- pub fn from_method(
- tcx: TyCtxt<'tcx>,
- trait_id: DefId,
- substs: SubstsRef<'tcx>,
- ) -> ty::TraitRef<'tcx> {
- let defs = tcx.generics_of(trait_id);
- tcx.mk_trait_ref(trait_id, tcx.mk_substs(&substs[..defs.params.len()]))
+ #[inline]
+ pub fn self_ty(&self) -> Ty<'tcx> {
+ self.substs.type_at(0)
}
}
@@ -907,7 +939,7 @@ impl<'tcx> ExistentialTraitRef<'tcx> {
// otherwise the escaping vars would be captured by the binder
// debug_assert!(!self_ty.has_escaping_bound_vars());
- tcx.mk_trait_ref(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter()))
+ ty::TraitRef::new(tcx, self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter()))
}
}
@@ -1158,9 +1190,9 @@ where
/// Represents the projection of an associated type.
///
-/// For a projection, this would be `<Ty as Trait<...>>::N`.
-///
-/// For an opaque type, there is no explicit syntax.
+/// * For a projection, this would be `<Ty as Trait<...>>::N<...>`.
+/// * For an inherent projection, this would be `Ty::N<...>`.
+/// * For an opaque type, there is no explicit syntax.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, TyEncodable, TyDecodable)]
#[derive(HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct AliasTy<'tcx> {
@@ -1169,12 +1201,16 @@ pub struct AliasTy<'tcx> {
/// For a projection, these are the substitutions for the trait and the
/// GAT substitutions, if there are any.
///
+ /// For an inherent projection, they consist of the self type and the GAT substitutions,
+ /// if there are any.
+ ///
/// For RPIT the substitutions are for the generics of the function,
/// while for TAIT it is used for the generic parameters of the alias.
pub substs: SubstsRef<'tcx>,
- /// The `DefId` of the `TraitItem` for the associated type `N` if this is a projection,
- /// or the `OpaqueType` item if this is an opaque.
+ /// The `DefId` of the `TraitItem` or `ImplItem` for the associated type `N` depending on whether
+ /// this is a projection or an inherent projection or the `DefId` of the `OpaqueType` item if
+ /// this is an opaque.
///
/// During codegen, `tcx.type_of(def_id)` can be used to get the type of the
/// underlying type if the type is an opaque.
@@ -1192,6 +1228,7 @@ pub struct AliasTy<'tcx> {
impl<'tcx> AliasTy<'tcx> {
pub fn kind(self, tcx: TyCtxt<'tcx>) -> ty::AliasKind {
match tcx.def_kind(self.def_id) {
+ DefKind::AssocTy if let DefKind::Impl { of_trait: false } = tcx.def_kind(tcx.parent(self.def_id)) => ty::Inherent,
DefKind::AssocTy | DefKind::ImplTraitPlaceholder => ty::Projection,
DefKind::OpaqueTy => ty::Opaque,
kind => bug!("unexpected DefKind in AliasTy: {kind:?}"),
@@ -1205,6 +1242,17 @@ impl<'tcx> AliasTy<'tcx> {
/// The following methods work only with associated type projections.
impl<'tcx> AliasTy<'tcx> {
+ pub fn self_ty(self) -> Ty<'tcx> {
+ self.substs.type_at(0)
+ }
+
+ pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
+ tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
+ }
+}
+
+/// The following methods work only with trait associated type projections.
+impl<'tcx> AliasTy<'tcx> {
pub fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId {
match tcx.def_kind(self.def_id) {
DefKind::AssocTy | DefKind::AssocConst => tcx.parent(self.def_id),
@@ -1217,7 +1265,7 @@ impl<'tcx> AliasTy<'tcx> {
/// Extracts the underlying trait reference and own substs from this projection.
/// For example, if this is a projection of `<T as StreamingIterator>::Item<'a>`,
- /// then this function would return a `T: Iterator` trait reference and `['a]` as the own substs
+ /// then this function would return a `T: StreamingIterator` trait reference and `['a]` as the own substs
pub fn trait_ref_and_own_substs(
self,
tcx: TyCtxt<'tcx>,
@@ -1226,7 +1274,7 @@ impl<'tcx> AliasTy<'tcx> {
let trait_def_id = self.trait_def_id(tcx);
let trait_generics = tcx.generics_of(trait_def_id);
(
- tcx.mk_trait_ref(trait_def_id, self.substs.truncate_to(tcx, trait_generics)),
+ ty::TraitRef::new(tcx, trait_def_id, self.substs.truncate_to(tcx, trait_generics)),
&self.substs[trait_generics.count()..],
)
}
@@ -1240,15 +1288,30 @@ impl<'tcx> AliasTy<'tcx> {
/// as well.
pub fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx> {
let def_id = self.trait_def_id(tcx);
- tcx.mk_trait_ref(def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
+ ty::TraitRef::new(tcx, def_id, self.substs.truncate_to(tcx, tcx.generics_of(def_id)))
}
+}
- pub fn self_ty(self) -> Ty<'tcx> {
- self.substs.type_at(0)
- }
+/// The following methods work only with inherent associated type projections.
+impl<'tcx> AliasTy<'tcx> {
+ /// Transform the substitutions to have the given `impl` substs as the base and the GAT substs on top of that.
+ ///
+ /// Does the following transformation:
+ ///
+ /// ```text
+ /// [Self, P_0...P_m] -> [I_0...I_n, P_0...P_m]
+ ///
+ /// I_i impl subst
+ /// P_j GAT subst
+ /// ```
+ pub fn rebase_substs_onto_impl(
+ self,
+ impl_substs: ty::SubstsRef<'tcx>,
+ tcx: TyCtxt<'tcx>,
+ ) -> ty::SubstsRef<'tcx> {
+ debug_assert_eq!(self.kind(tcx), ty::Inherent);
- pub fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self {
- tcx.mk_alias_ty(self.def_id, [self_ty.into()].into_iter().chain(self.substs.iter().skip(1)))
+ tcx.mk_substs_from_iter(impl_substs.into_iter().chain(self.substs.into_iter().skip(1)))
}
}
@@ -1436,7 +1499,7 @@ pub struct ConstVid<'tcx> {
rustc_index::newtype_index! {
/// A **region** (lifetime) **v**ariable **ID**.
#[derive(HashStable)]
- #[debug_format = "'_#{}r"]
+ #[debug_format = "'?{}"]
pub struct RegionVid {}
}
@@ -1645,7 +1708,9 @@ impl<'tcx> Region<'tcx> {
ty::ReErased => {
flags = flags | TypeFlags::HAS_RE_ERASED;
}
- ty::ReError(_) => {}
+ ty::ReError(_) => {
+ flags = flags | TypeFlags::HAS_FREE_REGIONS;
+ }
}
debug!("type_flags({:?}) = {:?}", self, flags);
@@ -2303,13 +2368,11 @@ impl<'tcx> Ty<'tcx> {
ty::Adt(def, _substs) => def.sized_constraint(tcx).0.is_empty(),
- ty::Alias(..) | ty::Param(_) => false,
+ ty::Alias(..) | ty::Param(_) | ty::Placeholder(..) => false,
ty::Infer(ty::TyVar(_)) => false,
- ty::Bound(..)
- | ty::Placeholder(..)
- | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
+ ty::Bound(..) | ty::Infer(ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("`is_trivially_sized` applied to unexpected type: {:?}", self)
}
}
@@ -2400,6 +2463,13 @@ impl<'tcx> Ty<'tcx> {
_ => None,
}
}
+
+ pub fn is_c_void(self, tcx: TyCtxt<'_>) -> bool {
+ match self.kind() {
+ ty::Adt(adt, _) => tcx.lang_items().get(LangItem::CVoid) == Some(adt.did()),
+ _ => false,
+ }
+ }
}
/// Extra information about why we ended up with a particular variance.
diff --git a/compiler/rustc_middle/src/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs
index f05b87343..43f95635a 100644
--- a/compiler/rustc_middle/src/ty/subst.rs
+++ b/compiler/rustc_middle/src/ty/subst.rs
@@ -21,7 +21,6 @@ use std::marker::PhantomData;
use std::mem;
use std::num::NonZeroUsize;
use std::ops::{ControlFlow, Deref};
-use std::slice;
/// An entity in the Rust type system, which can be one of
/// several kinds (types, lifetimes, and consts).
@@ -48,38 +47,13 @@ const TYPE_TAG: usize = 0b00;
const REGION_TAG: usize = 0b01;
const CONST_TAG: usize = 0b10;
-#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Debug, TyEncodable, TyDecodable, PartialEq, Eq, PartialOrd, Ord, HashStable)]
pub enum GenericArgKind<'tcx> {
Lifetime(ty::Region<'tcx>),
Type(Ty<'tcx>),
Const(ty::Const<'tcx>),
}
-/// This function goes from `&'a [Ty<'tcx>]` to `&'a [GenericArg<'tcx>]`
-///
-/// This is sound as, for types, `GenericArg` is just
-/// `NonZeroUsize::new_unchecked(ty as *const _ as usize)` as
-/// long as we use `0` for the `TYPE_TAG`.
-pub fn ty_slice_as_generic_args<'a, 'tcx>(ts: &'a [Ty<'tcx>]) -> &'a [GenericArg<'tcx>] {
- assert_eq!(TYPE_TAG, 0);
- // SAFETY: the whole slice is valid and immutable.
- // `Ty` and `GenericArg` is explained above.
- unsafe { slice::from_raw_parts(ts.as_ptr().cast(), ts.len()) }
-}
-
-impl<'tcx> List<Ty<'tcx>> {
- /// Allows to freely switch between `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>`.
- ///
- /// As lists are interned, `List<Ty<'tcx>>` and `List<GenericArg<'tcx>>` have
- /// be interned together, see `mk_type_list` for more details.
- #[inline]
- pub fn as_substs(&'tcx self) -> SubstsRef<'tcx> {
- assert_eq!(TYPE_TAG, 0);
- // SAFETY: `List<T>` is `#[repr(C)]`. `Ty` and `GenericArg` is explained above.
- unsafe { &*(self as *const List<Ty<'tcx>> as *const List<GenericArg<'tcx>>) }
- }
-}
-
impl<'tcx> GenericArgKind<'tcx> {
#[inline]
fn pack(self) -> GenericArg<'tcx> {
@@ -180,30 +154,45 @@ impl<'tcx> GenericArg<'tcx> {
}
}
- /// Unpack the `GenericArg` as a region when it is known certainly to be a region.
- pub fn expect_region(self) -> ty::Region<'tcx> {
+ #[inline]
+ pub fn as_type(self) -> Option<Ty<'tcx>> {
match self.unpack() {
- GenericArgKind::Lifetime(lt) => lt,
- _ => bug!("expected a region, but found another kind"),
+ GenericArgKind::Type(ty) => Some(ty),
+ _ => None,
}
}
+ #[inline]
+ pub fn as_region(self) -> Option<ty::Region<'tcx>> {
+ match self.unpack() {
+ GenericArgKind::Lifetime(re) => Some(re),
+ _ => None,
+ }
+ }
+
+ #[inline]
+ pub fn as_const(self) -> Option<ty::Const<'tcx>> {
+ match self.unpack() {
+ GenericArgKind::Const(ct) => Some(ct),
+ _ => None,
+ }
+ }
+
+ /// Unpack the `GenericArg` as a region when it is known certainly to be a region.
+ pub fn expect_region(self) -> ty::Region<'tcx> {
+ self.as_region().unwrap_or_else(|| bug!("expected a region, but found another kind"))
+ }
+
/// Unpack the `GenericArg` as a type when it is known certainly to be a type.
/// This is true in cases where `Substs` is used in places where the kinds are known
/// to be limited (e.g. in tuples, where the only parameters are type parameters).
pub fn expect_ty(self) -> Ty<'tcx> {
- match self.unpack() {
- GenericArgKind::Type(ty) => ty,
- _ => bug!("expected a type, but found another kind"),
- }
+ self.as_type().unwrap_or_else(|| bug!("expected a type, but found another kind"))
}
/// Unpack the `GenericArg` as a const when it is known certainly to be a const.
pub fn expect_const(self) -> ty::Const<'tcx> {
- match self.unpack() {
- GenericArgKind::Const(c) => c,
- _ => bug!("expected a const, but found another kind"),
- }
+ self.as_const().unwrap_or_else(|| bug!("expected a const, but found another kind"))
}
pub fn is_non_region_infer(self) -> bool {
@@ -268,13 +257,16 @@ pub type InternalSubsts<'tcx> = List<GenericArg<'tcx>>;
pub type SubstsRef<'tcx> = &'tcx InternalSubsts<'tcx>;
impl<'tcx> InternalSubsts<'tcx> {
- /// Checks whether all elements of this list are types, if so, transmute.
- pub fn try_as_type_list(&'tcx self) -> Option<&'tcx List<Ty<'tcx>>> {
- self.iter().all(|arg| matches!(arg.unpack(), GenericArgKind::Type(_))).then(|| {
- assert_eq!(TYPE_TAG, 0);
- // SAFETY: All elements are types, see `List<Ty<'tcx>>::as_substs`.
- unsafe { &*(self as *const List<GenericArg<'tcx>> as *const List<Ty<'tcx>>) }
- })
+ /// Converts substs to a type list.
+ ///
+ /// # Panics
+ ///
+ /// If any of the generic arguments are not types.
+ pub fn into_type_list(&self, tcx: TyCtxt<'tcx>) -> &'tcx List<Ty<'tcx>> {
+ tcx.mk_type_list_from_iter(self.iter().map(|arg| match arg.unpack() {
+ GenericArgKind::Type(ty) => ty,
+ _ => bug!("`into_type_list` called on substs with non-types"),
+ }))
}
/// Interpret these substitutions as the substitutions of a closure type.
@@ -379,22 +371,17 @@ impl<'tcx> InternalSubsts<'tcx> {
#[inline]
pub fn types(&'tcx self) -> impl DoubleEndedIterator<Item = Ty<'tcx>> + 'tcx {
- self.iter()
- .filter_map(|k| if let GenericArgKind::Type(ty) = k.unpack() { Some(ty) } else { None })
+ self.iter().filter_map(|k| k.as_type())
}
#[inline]
pub fn regions(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Region<'tcx>> + 'tcx {
- self.iter().filter_map(|k| {
- if let GenericArgKind::Lifetime(lt) = k.unpack() { Some(lt) } else { None }
- })
+ self.iter().filter_map(|k| k.as_region())
}
#[inline]
pub fn consts(&'tcx self) -> impl DoubleEndedIterator<Item = ty::Const<'tcx>> + 'tcx {
- self.iter().filter_map(|k| {
- if let GenericArgKind::Const(ct) = k.unpack() { Some(ct) } else { None }
- })
+ self.iter().filter_map(|k| k.as_const())
}
#[inline]
@@ -410,31 +397,21 @@ impl<'tcx> InternalSubsts<'tcx> {
#[inline]
#[track_caller]
pub fn type_at(&self, i: usize) -> Ty<'tcx> {
- if let GenericArgKind::Type(ty) = self[i].unpack() {
- ty
- } else {
- bug!("expected type for param #{} in {:?}", i, self);
- }
+ self[i].as_type().unwrap_or_else(|| bug!("expected type for param #{} in {:?}", i, self))
}
#[inline]
#[track_caller]
pub fn region_at(&self, i: usize) -> ty::Region<'tcx> {
- if let GenericArgKind::Lifetime(lt) = self[i].unpack() {
- lt
- } else {
- bug!("expected region for param #{} in {:?}", i, self);
- }
+ self[i]
+ .as_region()
+ .unwrap_or_else(|| bug!("expected region for param #{} in {:?}", i, self))
}
#[inline]
#[track_caller]
pub fn const_at(&self, i: usize) -> ty::Const<'tcx> {
- if let GenericArgKind::Const(ct) = self[i].unpack() {
- ct
- } else {
- bug!("expected const for param #{} in {:?}", i, self);
- }
+ self[i].as_const().unwrap_or_else(|| bug!("expected const for param #{} in {:?}", i, self))
}
#[inline]
@@ -635,6 +612,12 @@ where
) -> SubstIter<'s, 'tcx, I> {
SubstIter { it: self.0.into_iter(), tcx, substs }
}
+
+ /// Similar to [`subst_identity`](EarlyBinder::subst_identity),
+ /// but on an iterator of `TypeFoldable` values.
+ pub fn subst_identity_iter(self) -> I::IntoIter {
+ self.0.into_iter()
+ }
}
pub struct SubstIter<'s, 'tcx, I: IntoIterator> {
@@ -687,6 +670,12 @@ where
) -> SubstIterCopied<'s, 'tcx, I> {
SubstIterCopied { it: self.0.into_iter(), tcx, substs }
}
+
+ /// Similar to [`subst_identity`](EarlyBinder::subst_identity),
+ /// but on an iterator of values that deref to a `TypeFoldable`.
+ pub fn subst_identity_iter_copied(self) -> impl Iterator<Item = <I::Item as Deref>::Target> {
+ self.0.into_iter().map(|v| *v)
+ }
}
pub struct SubstIterCopied<'a, 'tcx, I: IntoIterator> {
@@ -772,7 +761,7 @@ impl<'tcx, T: TypeFoldable<TyCtxt<'tcx>>> ty::EarlyBinder<T> {
/// Returns the inner value, but only if it contains no bound vars.
pub fn no_bound_vars(self) -> Option<T> {
- if !self.0.needs_subst() { Some(self.0) } else { None }
+ if !self.0.has_param() { Some(self.0) } else { None }
}
}
@@ -840,12 +829,18 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for SubstFolder<'a, 'tcx> {
None => region_param_out_of_range(data, self.substs),
}
}
- _ => r,
+ ty::ReLateBound(..)
+ | ty::ReFree(_)
+ | ty::ReStatic
+ | ty::RePlaceholder(_)
+ | ty::ReErased
+ | ty::ReError(_) => r,
+ ty::ReVar(_) => bug!("unexpected region: {r:?}"),
}
}
fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> {
- if !t.needs_subst() {
+ if !t.has_param() {
return t;
}
diff --git a/compiler/rustc_middle/src/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs
index 6747da7ab..e61037e5e 100644
--- a/compiler/rustc_middle/src/ty/trait_def.rs
+++ b/compiler/rustc_middle/src/ty/trait_def.rs
@@ -139,40 +139,6 @@ impl<'tcx> TyCtxt<'tcx> {
treat_projections: TreatProjections,
mut f: impl FnMut(DefId),
) {
- let _: Option<()> =
- self.find_map_relevant_impl(trait_def_id, self_ty, treat_projections, |did| {
- f(did);
- None
- });
- }
-
- /// `trait_def_id` MUST BE the `DefId` of a trait.
- pub fn non_blanket_impls_for_ty(
- self,
- trait_def_id: DefId,
- self_ty: Ty<'tcx>,
- ) -> impl Iterator<Item = DefId> + 'tcx {
- let impls = self.trait_impls_of(trait_def_id);
- if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
- if let Some(impls) = impls.non_blanket_impls.get(&simp) {
- return impls.iter().copied();
- }
- }
-
- [].iter().copied()
- }
-
- /// Applies function to every impl that could possibly match the self type `self_ty` and returns
- /// the first non-none value.
- ///
- /// `trait_def_id` MUST BE the `DefId` of a trait.
- pub fn find_map_relevant_impl<T>(
- self,
- trait_def_id: DefId,
- self_ty: Ty<'tcx>,
- treat_projections: TreatProjections,
- mut f: impl FnMut(DefId) -> Option<T>,
- ) -> Option<T> {
// FIXME: This depends on the set of all impls for the trait. That is
// unfortunate wrt. incremental compilation.
//
@@ -181,9 +147,7 @@ impl<'tcx> TyCtxt<'tcx> {
let impls = self.trait_impls_of(trait_def_id);
for &impl_def_id in impls.blanket_impls.iter() {
- if let result @ Some(_) = f(impl_def_id) {
- return result;
- }
+ f(impl_def_id);
}
// Note that we're using `TreatParams::ForLookup` to query `non_blanket_impls` while using
@@ -199,20 +163,30 @@ impl<'tcx> TyCtxt<'tcx> {
if let Some(simp) = fast_reject::simplify_type(self, self_ty, treat_params) {
if let Some(impls) = impls.non_blanket_impls.get(&simp) {
for &impl_def_id in impls {
- if let result @ Some(_) = f(impl_def_id) {
- return result;
- }
+ f(impl_def_id);
}
}
} else {
for &impl_def_id in impls.non_blanket_impls.values().flatten() {
- if let result @ Some(_) = f(impl_def_id) {
- return result;
- }
+ f(impl_def_id);
}
}
+ }
- None
+ /// `trait_def_id` MUST BE the `DefId` of a trait.
+ pub fn non_blanket_impls_for_ty(
+ self,
+ trait_def_id: DefId,
+ self_ty: Ty<'tcx>,
+ ) -> impl Iterator<Item = DefId> + 'tcx {
+ let impls = self.trait_impls_of(trait_def_id);
+ if let Some(simp) = fast_reject::simplify_type(self, self_ty, TreatParams::AsCandidateKey) {
+ if let Some(impls) = impls.non_blanket_impls.get(&simp) {
+ return impls.iter().copied();
+ }
+ }
+
+ [].iter().copied()
}
/// Returns an iterator containing all impls for `trait_def_id`.
diff --git a/compiler/rustc_middle/src/ty/typeck_results.rs b/compiler/rustc_middle/src/ty/typeck_results.rs
index 47943b94c..e04dbbff9 100644
--- a/compiler/rustc_middle/src/ty/typeck_results.rs
+++ b/compiler/rustc_middle/src/ty/typeck_results.rs
@@ -20,7 +20,7 @@ use rustc_hir::{
hir_id::OwnerId,
HirId, ItemLocalId, ItemLocalMap, ItemLocalSet,
};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_middle::mir::FakeReadCause;
use rustc_session::Session;
@@ -151,10 +151,14 @@ pub struct TypeckResults<'tcx> {
/// this field will be set to `Some(ErrorGuaranteed)`.
pub tainted_by_errors: Option<ErrorGuaranteed>,
- /// All the opaque types that have hidden types set
- /// by this function. We also store the
- /// type here, so that mir-borrowck can use it as a hint for figuring out hidden types,
- /// even if they are only set in dead code (which doesn't show up in MIR).
+ /// All the opaque types that have hidden types set by this function.
+ /// We also store the type here, so that the compiler can use it as a hint
+ /// for figuring out hidden types, even if they are only set in dead code
+ /// (which doesn't show up in MIR).
+ ///
+ /// These types are mapped back to the opaque's identity substitutions
+ /// (with erased regions), which is why we don't associated substs with any
+ /// of these usages.
pub concrete_opaque_types: FxIndexMap<LocalDefId, ty::OpaqueHiddenType<'tcx>>,
/// Tracks the minimum captures required for a closure;
@@ -208,6 +212,9 @@ pub struct TypeckResults<'tcx> {
/// Contains the data for evaluating the effect of feature `capture_disjoint_fields`
/// on closure size.
pub closure_size_eval: FxHashMap<LocalDefId, ClosureSizeProfileData<'tcx>>,
+
+ /// Container types and field indices of `offset_of!` expressions
+ offset_of_data: ItemLocalMap<(Ty<'tcx>, Vec<FieldIdx>)>,
}
/// Whenever a value may be live across a generator yield, the type of that value winds up in the
@@ -280,6 +287,7 @@ impl<'tcx> TypeckResults<'tcx> {
generator_interior_predicates: Default::default(),
treat_byte_string_as_slice: Default::default(),
closure_size_eval: Default::default(),
+ offset_of_data: Default::default(),
}
}
@@ -530,6 +538,14 @@ impl<'tcx> TypeckResults<'tcx> {
pub fn coercion_casts(&self) -> &ItemLocalSet {
&self.coercion_casts
}
+
+ pub fn offset_of_data(&self) -> LocalTableInContext<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
+ LocalTableInContext { hir_owner: self.hir_owner, data: &self.offset_of_data }
+ }
+
+ pub fn offset_of_data_mut(&mut self) -> LocalTableInContextMut<'_, (Ty<'tcx>, Vec<FieldIdx>)> {
+ LocalTableInContextMut { hir_owner: self.hir_owner, data: &mut self.offset_of_data }
+ }
}
/// Validate that the given HirId (respectively its `local_id` part) can be
diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs
index c8a78ec03..ba0513563 100644
--- a/compiler/rustc_middle/src/ty/util.rs
+++ b/compiler/rustc_middle/src/ty/util.rs
@@ -2,7 +2,7 @@
use crate::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use crate::mir;
-use crate::ty::fast_reject::TreatProjections;
+use crate::query::Providers;
use crate::ty::layout::IntegerExt;
use crate::ty::{
self, FallibleTypeFolder, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable,
@@ -11,13 +11,13 @@ use crate::ty::{
use crate::ty::{GenericArgKind, SubstsRef};
use rustc_apfloat::Float as _;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
use rustc_errors::ErrorGuaranteed;
use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_index::bit_set::GrowableBitSet;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_macros::HashStable;
use rustc_session::Limit;
use rustc_span::sym;
@@ -35,9 +35,14 @@ pub struct Discr<'tcx> {
/// Used as an input to [`TyCtxt::uses_unique_generic_params`].
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum IgnoreRegions {
- Yes,
+pub enum CheckRegions {
No,
+ /// Only permit early bound regions. This is useful for Adts which
+ /// can never have late bound regions.
+ OnlyEarlyBound,
+ /// Permit both late bound and early bound regions. Use this for functions,
+ /// which frequently have late bound regions.
+ Bound,
}
#[derive(Copy, Clone, Debug)]
@@ -124,7 +129,7 @@ impl IntTypeExt for IntegerType {
impl<'tcx> TyCtxt<'tcx> {
/// Creates a hash of the type `Ty` which will be the same no matter what crate
/// context it's calculated within. This is used by the `type_id` intrinsic.
- pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
+ pub fn type_id_hash(self, ty: Ty<'tcx>) -> Hash64 {
// We want the type_id be independent of the types free regions, so we
// erase them. The erase_regions() call will also anonymize bound
// regions, which is desirable too.
@@ -359,21 +364,29 @@ impl<'tcx> TyCtxt<'tcx> {
self.ensure().coherent_trait(drop_trait);
let ty = self.type_of(adt_did).subst_identity();
- let (did, constness) = self.find_map_relevant_impl(
- drop_trait,
- ty,
- // FIXME: This could also be some other mode, like "unexpected"
- TreatProjections::ForLookup,
- |impl_did| {
- if let Some(item_id) = self.associated_item_def_ids(impl_did).first() {
- if validate(self, impl_did).is_ok() {
- return Some((*item_id, self.constness(impl_did)));
- }
- }
- None
- },
- )?;
+ let mut dtor_candidate = None;
+ self.for_each_relevant_impl(drop_trait, ty, |impl_did| {
+ if validate(self, impl_did).is_err() {
+ // Already `ErrorGuaranteed`, no need to delay a span bug here.
+ return;
+ }
+ let Some(item_id) = self.associated_item_def_ids(impl_did).first() else {
+ self.sess.delay_span_bug(self.def_span(impl_did), "Drop impl without drop function");
+ return;
+ };
+
+ if let Some((old_item_id, _)) = dtor_candidate {
+ self.sess
+ .struct_span_err(self.def_span(item_id), "multiple drop impls found")
+ .span_note(self.def_span(old_item_id), "other impl here")
+ .delay_as_bug();
+ }
+
+ dtor_candidate = Some((*item_id, self.constness(impl_did)));
+ });
+
+ let (did, constness) = dtor_candidate?;
Some(ty::Destructor { did, constness })
}
@@ -461,21 +474,28 @@ impl<'tcx> TyCtxt<'tcx> {
pub fn uses_unique_generic_params(
self,
substs: SubstsRef<'tcx>,
- ignore_regions: IgnoreRegions,
+ ignore_regions: CheckRegions,
) -> Result<(), NotUniqueParam<'tcx>> {
let mut seen = GrowableBitSet::default();
+ let mut seen_late = FxHashSet::default();
for arg in substs {
match arg.unpack() {
- GenericArgKind::Lifetime(lt) => {
- if ignore_regions == IgnoreRegions::No {
- let ty::ReEarlyBound(p) = lt.kind() else {
- return Err(NotUniqueParam::NotParam(lt.into()))
- };
+ GenericArgKind::Lifetime(lt) => match (ignore_regions, lt.kind()) {
+ (CheckRegions::Bound, ty::ReLateBound(di, reg)) => {
+ if !seen_late.insert((di, reg)) {
+ return Err(NotUniqueParam::DuplicateParam(lt.into()));
+ }
+ }
+ (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, ty::ReEarlyBound(p)) => {
if !seen.insert(p.index) {
return Err(NotUniqueParam::DuplicateParam(lt.into()));
}
}
- }
+ (CheckRegions::OnlyEarlyBound | CheckRegions::Bound, _) => {
+ return Err(NotUniqueParam::NotParam(lt.into()));
+ }
+ (CheckRegions::No, _) => {}
+ },
GenericArgKind::Type(t) => match t.kind() {
ty::Param(p) => {
if !seen.insert(p.index) {
@@ -498,6 +518,42 @@ impl<'tcx> TyCtxt<'tcx> {
Ok(())
}
+ /// Checks whether each generic argument is simply a unique generic placeholder.
+ ///
+ /// This is used in the new solver, which canonicalizes params to placeholders
+ /// for better caching.
+ pub fn uses_unique_placeholders_ignoring_regions(
+ self,
+ substs: SubstsRef<'tcx>,
+ ) -> Result<(), NotUniqueParam<'tcx>> {
+ let mut seen = GrowableBitSet::default();
+ for arg in substs {
+ match arg.unpack() {
+ // Ignore regions, since we can't resolve those in a canonicalized
+ // query in the trait solver.
+ GenericArgKind::Lifetime(_) => {}
+ GenericArgKind::Type(t) => match t.kind() {
+ ty::Placeholder(p) => {
+ if !seen.insert(p.bound.var) {
+ return Err(NotUniqueParam::DuplicateParam(t.into()));
+ }
+ }
+ _ => return Err(NotUniqueParam::NotParam(t.into())),
+ },
+ GenericArgKind::Const(c) => match c.kind() {
+ ty::ConstKind::Placeholder(p) => {
+ if !seen.insert(p.bound) {
+ return Err(NotUniqueParam::DuplicateParam(c.into()));
+ }
+ }
+ _ => return Err(NotUniqueParam::NotParam(c.into())),
+ },
+ }
+ }
+
+ Ok(())
+ }
+
/// Returns `true` if `def_id` refers to a closure (e.g., `|x| x * 2`). Note
/// that closures have a `DefId`, but the closure *expression* also
/// has a `HirId` that is located within the context where the
@@ -642,16 +698,16 @@ impl<'tcx> TyCtxt<'tcx> {
}
}
- /// Return the set of types that should be taken into accound when checking
+ /// Return the set of types that should be taken into account when checking
/// trait bounds on a generator's internal state.
pub fn generator_hidden_types(
self,
def_id: DefId,
) -> impl Iterator<Item = ty::EarlyBinder<Ty<'tcx>>> {
- let generator_layout = &self.mir_generator_witnesses(def_id);
+ let generator_layout = self.mir_generator_witnesses(def_id);
generator_layout
- .field_tys
- .iter()
+ .as_ref()
+ .map_or_else(|| [].iter(), |l| l.field_tys.iter())
.filter(|decl| !decl.ignore_for_traits)
.map(|decl| ty::EarlyBinder(decl.ty))
}
@@ -694,20 +750,6 @@ impl<'tcx> TyCtxt<'tcx> {
if visitor.found_recursion { Err(expanded_type) } else { Ok(expanded_type) }
}
- pub fn bound_return_position_impl_trait_in_trait_tys(
- self,
- def_id: DefId,
- ) -> ty::EarlyBinder<Result<&'tcx FxHashMap<DefId, Ty<'tcx>>, ErrorGuaranteed>> {
- ty::EarlyBinder(self.collect_return_position_impl_trait_in_trait_tys(def_id))
- }
-
- pub fn bound_explicit_item_bounds(
- self,
- def_id: DefId,
- ) -> ty::EarlyBinder<&'tcx [(ty::Predicate<'tcx>, rustc_span::Span)]> {
- ty::EarlyBinder(self.explicit_item_bounds(def_id))
- }
-
/// Returns names of captured upvars for closures and generators.
///
/// Here are some examples:
@@ -1158,7 +1200,7 @@ impl<'tcx> Ty<'tcx> {
// context, or *something* like that, but for now just avoid passing inference
// variables to queries that can't cope with them. Instead, conservatively
// return "true" (may change drop order).
- if query_ty.needs_infer() {
+ if query_ty.has_infer() {
return true;
}
@@ -1260,7 +1302,7 @@ pub enum ExplicitSelf<'tcx> {
impl<'tcx> ExplicitSelf<'tcx> {
/// Categorizes an explicit self declaration like `self: SomeType`
- /// into either `self`, `&self`, `&mut self`, `Box<self>`, or
+ /// into either `self`, `&self`, `&mut self`, `Box<Self>`, or
/// `Other`.
/// This is mainly used to require the arbitrary_self_types feature
/// in the case of `Other`, to improve error messages in the common cases,
@@ -1402,7 +1444,7 @@ pub fn is_trivially_const_drop(ty: Ty<'_>) -> bool {
}
/// Does the equivalent of
-/// ```ignore (ilustrative)
+/// ```ignore (illustrative)
/// let v = self.iter().map(|p| p.fold_with(folder)).collect::<SmallVec<[_; 8]>>();
/// folder.tcx().intern_*(&v)
/// ```
@@ -1479,8 +1521,8 @@ pub fn is_intrinsic(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool {
matches!(tcx.fn_sig(def_id).skip_binder().abi(), Abi::RustIntrinsic | Abi::PlatformIntrinsic)
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
reveal_opaque_types_in_bounds,
is_doc_hidden,
is_doc_notable_trait,
diff --git a/compiler/rustc_middle/src/ty/visit.rs b/compiler/rustc_middle/src/ty/visit.rs
index 08a62c900..520bb55e0 100644
--- a/compiler/rustc_middle/src/ty/visit.rs
+++ b/compiler/rustc_middle/src/ty/visit.rs
@@ -33,6 +33,14 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
}
fn has_type_flags(&self, flags: TypeFlags) -> bool {
+ // N.B. Even though this uses a visitor, the visitor does not actually
+ // recurse through the whole `TypeVisitable` implementor type.
+ //
+ // Instead it stops on the first "level", visiting types, regions,
+ // consts and predicates just fetches their type flags.
+ //
+ // Thus this is a lot faster than it might seem and should be
+ // optimized to a simple field access.
let res =
self.visit_with(&mut HasTypeFlagsVisitor { flags }).break_value() == Some(FoundFlags);
trace!(?self, ?flags, ?res, "has_type_flags");
@@ -41,6 +49,9 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
fn has_projections(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_PROJECTION)
}
+ fn has_inherent_projections(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_TY_INHERENT)
+ }
fn has_opaque_types(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_OPAQUE)
}
@@ -62,7 +73,7 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
}
}
fn has_non_region_param(&self) -> bool {
- self.has_type_flags(TypeFlags::NEEDS_SUBST - TypeFlags::HAS_RE_PARAM)
+ self.has_type_flags(TypeFlags::HAS_PARAM - TypeFlags::HAS_RE_PARAM)
}
fn has_infer_regions(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_RE_INFER)
@@ -71,10 +82,10 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
self.has_type_flags(TypeFlags::HAS_TY_INFER)
}
fn has_non_region_infer(&self) -> bool {
- self.has_type_flags(TypeFlags::NEEDS_INFER - TypeFlags::HAS_RE_INFER)
+ self.has_type_flags(TypeFlags::HAS_INFER - TypeFlags::HAS_RE_INFER)
}
- fn needs_infer(&self) -> bool {
- self.has_type_flags(TypeFlags::NEEDS_INFER)
+ fn has_infer(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_INFER)
}
fn has_placeholders(&self) -> bool {
self.has_type_flags(
@@ -86,8 +97,8 @@ pub trait TypeVisitableExt<'tcx>: TypeVisitable<TyCtxt<'tcx>> {
fn has_non_region_placeholders(&self) -> bool {
self.has_type_flags(TypeFlags::HAS_TY_PLACEHOLDER | TypeFlags::HAS_CT_PLACEHOLDER)
}
- fn needs_subst(&self) -> bool {
- self.has_type_flags(TypeFlags::NEEDS_SUBST)
+ fn has_param(&self) -> bool {
+ self.has_type_flags(TypeFlags::HAS_PARAM)
}
/// "Free" regions in this context means that it has any region
/// that is not (a) erased or (b) late-bound.
@@ -364,7 +375,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for ValidateBoundVars<'tcx> {
_ => (),
};
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_middle/src/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs
index 182945b9c..04a635a68 100644
--- a/compiler/rustc_middle/src/ty/walk.rs
+++ b/compiler/rustc_middle/src/ty/walk.rs
@@ -194,7 +194,7 @@ fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>)
| ty::FnDef(_, substs) => {
stack.extend(substs.iter().rev());
}
- ty::Tuple(ts) => stack.extend(ts.as_substs().iter().rev()),
+ ty::Tuple(ts) => stack.extend(ts.iter().rev().map(GenericArg::from)),
ty::GeneratorWitness(ts) => {
stack.extend(ts.skip_binder().iter().rev().map(|ty| ty.into()));
}
diff --git a/compiler/rustc_middle/src/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs
index b73ae5939..43ee0343f 100644
--- a/compiler/rustc_middle/src/util/bug.rs
+++ b/compiler/rustc_middle/src/util/bug.rs
@@ -31,8 +31,8 @@ fn opt_span_bug_fmt<S: Into<MultiSpan>>(
tls::with_opt(move |tcx| {
let msg = format!("{}: {}", location, args);
match (tcx, span) {
- (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, &msg),
- (Some(tcx), None) => tcx.sess.diagnostic().bug(&msg),
+ (Some(tcx), Some(span)) => tcx.sess.diagnostic().span_bug(span, msg),
+ (Some(tcx), None) => tcx.sess.diagnostic().bug(msg),
(None, _) => panic_any(msg),
}
})
@@ -48,6 +48,6 @@ pub fn trigger_delay_span_bug(tcx: TyCtxt<'_>, key: rustc_hir::def_id::DefId) {
);
}
-pub fn provide(providers: &mut crate::ty::query::Providers) {
- *providers = crate::ty::query::Providers { trigger_delay_span_bug, ..*providers };
+pub fn provide(providers: &mut crate::query::Providers) {
+ *providers = crate::query::Providers { trigger_delay_span_bug, ..*providers };
}
diff --git a/compiler/rustc_const_eval/src/util/call_kind.rs b/compiler/rustc_middle/src/util/call_kind.rs
index 995363c0e..98d55ea6d 100644
--- a/compiler/rustc_const_eval/src/util/call_kind.rs
+++ b/compiler/rustc_middle/src/util/call_kind.rs
@@ -2,10 +2,10 @@
//! as well as errors when attempting to call a non-const function in a const
//! context.
+use crate::ty::subst::SubstsRef;
+use crate::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
use rustc_hir::def_id::DefId;
use rustc_hir::{lang_items, LangItem};
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{AssocItemContainer, Instance, ParamEnv, Ty, TyCtxt};
use rustc_span::symbol::Ident;
use rustc_span::{sym, DesugaringKind, Span};
@@ -19,6 +19,8 @@ pub enum CallDesugaringKind {
QuestionFromResidual,
/// try { ..; x } calls type_of(x)::from_output(x)
TryBlockFromOutput,
+ /// `.await` calls `IntoFuture::into_future`
+ Await,
}
impl CallDesugaringKind {
@@ -29,6 +31,7 @@ impl CallDesugaringKind {
tcx.require_lang_item(LangItem::Try, None)
}
Self::QuestionFromResidual => tcx.get_diagnostic_item(sym::FromResidual).unwrap(),
+ Self::Await => tcx.get_diagnostic_item(sym::IntoFuture).unwrap(),
}
}
}
@@ -129,6 +132,8 @@ pub fn call_kind<'tcx>(
&& fn_call_span.desugaring_kind() == Some(DesugaringKind::TryBlock)
{
Some((CallDesugaringKind::TryBlockFromOutput, method_substs.type_at(0)))
+ } else if fn_call_span.is_desugaring(DesugaringKind::Await) {
+ Some((CallDesugaringKind::Await, method_substs.type_at(0)))
} else {
None
};
diff --git a/compiler/rustc_const_eval/src/util/find_self_call.rs b/compiler/rustc_middle/src/util/find_self_call.rs
index 33ad128ee..0eab0adf0 100644
--- a/compiler/rustc_const_eval/src/util/find_self_call.rs
+++ b/compiler/rustc_middle/src/util/find_self_call.rs
@@ -1,6 +1,6 @@
-use rustc_middle::mir::*;
-use rustc_middle::ty::subst::SubstsRef;
-use rustc_middle::ty::{self, TyCtxt};
+use crate::mir::*;
+use crate::ty::subst::SubstsRef;
+use crate::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
/// Checks if the specified `local` is used as the `self` parameter of a method call
diff --git a/compiler/rustc_middle/src/util/mod.rs b/compiler/rustc_middle/src/util/mod.rs
new file mode 100644
index 000000000..53b425789
--- /dev/null
+++ b/compiler/rustc_middle/src/util/mod.rs
@@ -0,0 +1,7 @@
+pub mod bug;
+pub mod call_kind;
+pub mod common;
+pub mod find_self_call;
+
+pub use call_kind::{call_kind, CallDesugaringKind, CallKind};
+pub use find_self_call::find_self_call;
diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs
index 55aa4fcff..c62c33d4d 100644
--- a/compiler/rustc_middle/src/values.rs
+++ b/compiler/rustc_middle/src/values.rs
@@ -106,6 +106,12 @@ impl<'tcx> Value<TyCtxt<'tcx>, DepKind> for ty::EarlyBinder<ty::Binder<'_, ty::F
}
}
+impl<'tcx, T> Value<TyCtxt<'tcx>, DepKind> for Result<T, ty::layout::LayoutError<'_>> {
+ fn from_cycle_error(_tcx: TyCtxt<'tcx>, _cycle: &[QueryInfo<DepKind>]) -> Self {
+ Err(ty::layout::LayoutError::Cycle)
+ }
+}
+
// item_and_field_ids should form a cycle where each field contains the
// type in the next element in the list
pub fn recursive_type_error(
@@ -158,8 +164,8 @@ pub fn recursive_type_error(
}
let items_list = {
let mut s = String::new();
- for (i, (item_id, _)) in item_and_field_ids.iter().enumerate() {
- let path = tcx.def_path_str(item_id.to_def_id());
+ for (i, &(item_id, _)) in item_and_field_ids.iter().enumerate() {
+ let path = tcx.def_path_str(item_id);
write!(&mut s, "`{path}`").unwrap();
if i == (ITEM_LIMIT - 1) && cycle_len > ITEM_LIMIT {
write!(&mut s, " and {} more", cycle_len - 5).unwrap();
diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml
index f24b165d7..58449ee9e 100644
--- a/compiler/rustc_mir_build/Cargo.toml
+++ b/compiler/rustc_mir_build/Cargo.toml
@@ -14,6 +14,7 @@ rustc_apfloat = { path = "../rustc_apfloat" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_index = { path = "../rustc_index" }
rustc_errors = { path = "../rustc_errors" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_mir_build/messages.ftl b/compiler/rustc_mir_build/messages.ftl
index f346cd483..cb265cf2c 100644
--- a/compiler/rustc_mir_build/messages.ftl
+++ b/compiler/rustc_mir_build/messages.ftl
@@ -1,62 +1,40 @@
-mir_build_unconditional_recursion = function cannot return without recursing
- .label = cannot return without recursing
- .help = a `loop` may express intention better if this is on purpose
-
-mir_build_unconditional_recursion_call_site_label = recursive call site
-
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
- call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
-mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
- call to unsafe function is unsafe and requires unsafe block (error E0133)
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
-mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
- use of inline assembly is unsafe and requires unsafe block (error E0133)
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
+mir_build_adt_defined_here = `{$ty}` defined here
-mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
- block (error E0133)
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
-mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
- use of mutable static is unsafe and requires unsafe block (error E0133)
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
-mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
- use of extern static is unsafe and requires unsafe block (error E0133)
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
- dereference of raw pointer is unsafe and requires unsafe block (error E0133)
- .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
- .label = dereference of raw pointer
+mir_build_bindings_with_variant_name =
+ pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
+ .suggestion = to match on the variant, qualify the path
-mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
- access to union field is unsafe and requires unsafe block (error E0133)
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
+mir_build_borrow = value is borrowed by `{$name}` here
-mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
- mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
+mir_build_borrow_of_layout_constrained_field_requires_unsafe =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
+ .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+ .label = borrow of layout constrained field with interior mutability
-mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
.note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
.label = borrow of layout constrained field with interior mutability
-mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+mir_build_borrow_of_moved_value = borrow of moved value
+ .label = value moved into `{$name}` here
+ .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
+ .value_borrowed_label = value borrowed here after move
+ .suggestion = borrow this binding in the pattern to avoid moving the value
+
+mir_build_call_to_fn_with_requires_unsafe =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
+ .note = can only be called if the required target features are available
+ .label = call to function with `#[target_feature]`
+
+mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
.note = can only be called if the required target features are available
.label = call to function with `#[target_feature]`
@@ -70,55 +48,24 @@ mir_build_call_to_unsafe_fn_requires_unsafe_nameless =
.note = consult the function's documentation for information on how to avoid undefined behavior
.label = call to unsafe function
-mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- call to unsafe function `{$function}` is unsafe and requires unsafe function or block
- .note = consult the function's documentation for information on how to avoid undefined behavior
- .label = call to unsafe function
-
mir_build_call_to_unsafe_fn_requires_unsafe_nameless_unsafe_op_in_unsafe_fn_allowed =
call to unsafe function is unsafe and requires unsafe function or block
.note = consult the function's documentation for information on how to avoid undefined behavior
.label = call to unsafe function
-mir_build_inline_assembly_requires_unsafe =
- use of inline assembly is unsafe and requires unsafe block
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
-
-mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of inline assembly is unsafe and requires unsafe function or block
- .note = inline assembly is entirely unchecked and can cause undefined behavior
- .label = use of inline assembly
-
-mir_build_initializing_type_with_requires_unsafe =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
-
-mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
- .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
- .label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_build_call_to_unsafe_fn_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ call to unsafe function `{$function}` is unsafe and requires unsafe function or block
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
-mir_build_mutable_static_requires_unsafe =
- use of mutable static is unsafe and requires unsafe block
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
-mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of mutable static is unsafe and requires unsafe function or block
- .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
- .label = use of mutable static
+mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
-mir_build_extern_static_requires_unsafe =
- use of extern static is unsafe and requires unsafe block
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_const_pattern_depends_on_generic_parameter =
+ constant pattern depends on a generic parameter
-mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- use of extern static is unsafe and requires unsafe function or block
- .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
- .label = use of extern static
+mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
mir_build_deref_raw_pointer_requires_unsafe =
dereference of raw pointer is unsafe and requires unsafe block
@@ -130,117 +77,46 @@ mir_build_deref_raw_pointer_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
.note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
.label = dereference of raw pointer
-mir_build_union_field_requires_unsafe =
- access to union field is unsafe and requires unsafe block
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
-
-mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- access to union field is unsafe and requires unsafe function or block
- .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
- .label = access to union field
-
-mir_build_mutation_of_layout_constrained_field_requires_unsafe =
- mutation of layout constrained field is unsafe and requires unsafe block
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
-
-mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- mutation of layout constrained field is unsafe and requires unsafe function or block
- .note = mutating layout constrained fields cannot statically be checked for valid values
- .label = mutation of layout constrained field
-
-mir_build_borrow_of_layout_constrained_field_requires_unsafe =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe block
- .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
- .label = borrow of layout constrained field with interior mutability
-
-mir_build_borrow_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- borrow of layout constrained field with interior mutability is unsafe and requires unsafe function or block
- .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
- .label = borrow of layout constrained field with interior mutability
-
-mir_build_call_to_fn_with_requires_unsafe =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block
- .note = can only be called if the required target features are available
- .label = call to function with `#[target_feature]`
-
-mir_build_call_to_fn_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
- call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe function or block
- .note = can only be called if the required target features are available
- .label = call to function with `#[target_feature]`
-
-mir_build_unused_unsafe = unnecessary `unsafe` block
- .label = unnecessary `unsafe` block
-
-mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
-mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
-
-mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
- .def_note = `{$peeled_ty}` defined here
- .type_note = the matched value is of type `{$ty}`
- .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
- .reference_note = references are always considered inhabited
- .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
- .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
-
-mir_build_static_in_pattern = statics cannot be referenced in patterns
-
-mir_build_assoc_const_in_pattern = associated consts cannot be referenced in patterns
-
-mir_build_const_param_in_pattern = const parameters cannot be referenced in patterns
+mir_build_extern_static_requires_unsafe =
+ use of extern static is unsafe and requires unsafe block
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
-mir_build_non_const_path = runtime values cannot be referenced in patterns
+mir_build_extern_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of extern static is unsafe and requires unsafe function or block
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
-mir_build_unreachable_pattern = unreachable pattern
- .label = unreachable pattern
- .catchall_label = matches any value
+mir_build_float_pattern = floating-point types cannot be used in patterns
-mir_build_const_pattern_depends_on_generic_parameter =
- constant pattern depends on a generic parameter
+mir_build_indirect_structural_match =
+ to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
-mir_build_could_not_eval_const_pattern = could not evaluate constant pattern
+mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
-mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
- lower range bound must be less than or equal to upper
- .label = lower bound larger than upper bound
- .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
+mir_build_initializing_type_with_requires_unsafe =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe block
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_build_literal_in_range_out_of_bounds =
- literal out of range for `{$ty}`
- .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
+mir_build_initializing_type_with_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe function or block
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
-mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
+mir_build_inline_assembly_requires_unsafe =
+ use of inline assembly is unsafe and requires unsafe block
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
-mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
- [one] pattern
- *[other] patterns
- } in let chain
- .note = {$count ->
- [one] this pattern
- *[other] these patterns
- } will always match
- .help = consider moving {$count ->
- [one] it
- *[other] them
- } outside of the construct
+mir_build_inline_assembly_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of inline assembly is unsafe and requires unsafe function or block
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
-mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
- [one] pattern
- *[other] patterns
- } in let chain
- .note = {$count ->
- [one] this pattern
- *[other] these patterns
- } will always match
- .help = consider moving {$count ->
- [one] it
- *[other] them
- } into the body
+mir_build_interpreted_as_const = introduce a variable instead
-mir_build_bindings_with_variant_name =
- pattern binding `{$name}` is named the same as one of the variants of the type `{$ty_path}`
- .suggestion = to match on the variant, qualify the path
+mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
mir_build_irrefutable_let_patterns_if_let = irrefutable `if let` {$count ->
[one] pattern
@@ -282,78 +158,97 @@ mir_build_irrefutable_let_patterns_while_let = irrefutable `while let` {$count -
} will always match, so the loop will never exit
.help = consider instead using a `loop {"{"} ... {"}"}` with a `let` inside it
-mir_build_borrow_of_moved_value = borrow of moved value
- .label = value moved into `{$name}` here
- .occurs_because_label = move occurs because `{$name}` has type `{$ty}` which does not implement the `Copy` trait
- .value_borrowed_label = value borrowed here after move
- .suggestion = borrow this binding in the pattern to avoid moving the value
+mir_build_leading_irrefutable_let_patterns = leading irrefutable {$count ->
+ [one] pattern
+ *[other] patterns
+ } in let chain
+ .note = {$count ->
+ [one] this pattern
+ *[other] these patterns
+ } will always match
+ .help = consider moving {$count ->
+ [one] it
+ *[other] them
+ } outside of the construct
-mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
+mir_build_literal_in_range_out_of_bounds =
+ literal out of range for `{$ty}`
+ .label = this value doesn't fit in `{$ty}` whose maximum value is `{$max}`
-mir_build_already_borrowed = cannot borrow value as mutable because it is also borrowed as immutable
+mir_build_lower_range_bound_must_be_less_than_or_equal_to_upper =
+ lower range bound must be less than or equal to upper
+ .label = lower bound larger than upper bound
+ .teach_note = When matching against a range, the compiler verifies that the range is non-empty. Range patterns include both end-points, so this is equivalent to requiring the start of the range to be less than or equal to the end of the range.
-mir_build_already_mut_borrowed = cannot borrow value as immutable because it is also borrowed as mutable
+mir_build_lower_range_bound_must_be_less_than_upper = lower range bound must be less than upper
-mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
+mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
-mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
+mir_build_moved = value is moved into `{$name}` here
-mir_build_borrow = value is borrowed by `{$name}` here
+mir_build_moved_while_borrowed = cannot move out of value because it is borrowed
-mir_build_moved = value is moved into `{$name}` here
+mir_build_multiple_mut_borrows = cannot borrow value as mutable more than once at a time
-mir_build_union_pattern = cannot use unions in constant patterns
+mir_build_mutable_borrow = value is mutably borrowed by `{$name}` here
-mir_build_type_not_structural =
- to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_mutable_static_requires_unsafe =
+ use of mutable static is unsafe and requires unsafe block
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
-mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+mir_build_mutable_static_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ use of mutable static is unsafe and requires unsafe function or block
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
-mir_build_invalid_pattern = `{$non_sm_ty}` cannot be used in patterns
+mir_build_mutation_of_layout_constrained_field_requires_unsafe =
+ mutation of layout constrained field is unsafe and requires unsafe block
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
-mir_build_float_pattern = floating-point types cannot be used in patterns
+mir_build_mutation_of_layout_constrained_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ mutation of layout constrained field is unsafe and requires unsafe function or block
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
-mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
+mir_build_non_const_path = runtime values cannot be referenced in patterns
-mir_build_indirect_structural_match =
- to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
+ .help = ensure that all variants are matched explicitly by adding the suggested match arms
+ .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
+
+mir_build_non_exhaustive_patterns_type_not_empty = non-exhaustive patterns: type `{$ty}` is non-empty
+ .def_note = `{$peeled_ty}` defined here
+ .type_note = the matched value is of type `{$ty}`
+ .non_exhaustive_type_note = the matched value is of type `{$ty}`, which is marked as non-exhaustive
+ .reference_note = references are always considered inhabited
+ .suggestion = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern as shown
+ .help = ensure that all possible cases are being handled by adding a match arm with a wildcard pattern
mir_build_nontrivial_structural_match =
to use a constant of type `{$non_sm_ty}` in a pattern, the constant's initializer must be trivial or `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
-mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
-
-mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-
mir_build_overlapping_range_endpoints = multiple patterns overlap on their endpoints
.range = ... with this range
.note = you likely meant to write mutually exclusive ranges
-mir_build_non_exhaustive_omitted_pattern = some variants are not matched explicitly
- .help = ensure that all variants are matched explicitly by adding the suggested match arms
- .note = the matched value is of type `{$scrut_ty}` and the `non_exhaustive_omitted_patterns` attribute was found
-
-mir_build_uncovered = {$count ->
- [1] pattern `{$witness_1}`
- [2] patterns `{$witness_1}` and `{$witness_2}`
- [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
- *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
- } not covered
-
mir_build_pattern_not_covered = refutable pattern in {$origin}
.pattern_ty = the matched value is of type `{$pattern_ty}`
-mir_build_inform_irrefutable = `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant
+mir_build_pointer_pattern = function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details.
-mir_build_more_information = for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html
+mir_build_privately_uninhabited = pattern `{$witness_1}` is currently uninhabited, but this variant contains private fields which may become inhabited in the future
-mir_build_adt_defined_here = `{$ty}` defined here
+mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
+ .attributes = no other attributes may be applied
+ .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
+ .missing_box = `#[rustc_box]` requires the `owned_box` lang item
-mir_build_variant_defined_here = not covered
+mir_build_static_in_pattern = statics cannot be referenced in patterns
-mir_build_interpreted_as_const = introduce a variable instead
+mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
-mir_build_confused = missing patterns are not covered because `{$variable}` is interpreted as a constant pattern, not a new variable
mir_build_suggest_if_let = you might want to use `if let` to ignore the {$count ->
[one] variant that isn't
@@ -365,10 +260,117 @@ mir_build_suggest_let_else = you might want to use `let else` to handle the {$co
*[other] variants that aren't
} matched
-mir_build_suggest_attempted_int_lit = alternatively, you could prepend the pattern with an underscore to define a new named variable; identifiers cannot begin with digits
+mir_build_trailing_irrefutable_let_patterns = trailing irrefutable {$count ->
+ [one] pattern
+ *[other] patterns
+ } in let chain
+ .note = {$count ->
+ [one] this pattern
+ *[other] these patterns
+ } will always match
+ .help = consider moving {$count ->
+ [one] it
+ *[other] them
+ } into the body
+
+mir_build_type_not_structural =
+ to use a constant of type `{$non_sm_ty}` in a pattern, `{$non_sm_ty}` must be annotated with `#[derive(PartialEq, Eq)]`
+mir_build_type_not_structural_more_info = see https://doc.rust-lang.org/stable/std/marker/trait.StructuralEq.html for details
-mir_build_rustc_box_attribute_error = `#[rustc_box]` attribute used incorrectly
- .attributes = no other attributes may be applied
- .not_box = `#[rustc_box]` may only be applied to a `Box::new()` call
- .missing_box = `#[rustc_box]` requires the `owned_box` lang item
+mir_build_type_not_structural_tip = the traits must be derived, manual `impl`s are not sufficient
+
+mir_build_unconditional_recursion = function cannot return without recursing
+ .label = cannot return without recursing
+ .help = a `loop` may express intention better if this is on purpose
+
+mir_build_unconditional_recursion_call_site_label = recursive call site
+
+mir_build_uncovered = {$count ->
+ [1] pattern `{$witness_1}`
+ [2] patterns `{$witness_1}` and `{$witness_2}`
+ [3] patterns `{$witness_1}`, `{$witness_2}` and `{$witness_3}`
+ *[other] patterns `{$witness_1}`, `{$witness_2}`, `{$witness_3}` and {$remainder} more
+ } not covered
+
+mir_build_union_field_requires_unsafe =
+ access to union field is unsafe and requires unsafe block
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_union_field_requires_unsafe_unsafe_op_in_unsafe_fn_allowed =
+ access to union field is unsafe and requires unsafe function or block
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_union_pattern = cannot use unions in constant patterns
+
+mir_build_unreachable_pattern = unreachable pattern
+ .label = unreachable pattern
+ .catchall_label = matches any value
+
+mir_build_unsafe_op_in_unsafe_fn_borrow_of_layout_constrained_field_requires_unsafe =
+ borrow of layout constrained field with interior mutability is unsafe and requires unsafe block (error E0133)
+ .note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+ .label = borrow of layout constrained field with interior mutability
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_fn_with_requires_unsafe =
+ call to function `{$function}` with `#[target_feature]` is unsafe and requires unsafe block (error E0133)
+ .note = can only be called if the required target features are available
+ .label = call to function with `#[target_feature]`
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe =
+ call to unsafe function `{$function}` is unsafe and requires unsafe block (error E0133)
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_call_to_unsafe_fn_requires_unsafe_nameless =
+ call to unsafe function is unsafe and requires unsafe block (error E0133)
+ .note = consult the function's documentation for information on how to avoid undefined behavior
+ .label = call to unsafe function
+
+mir_build_unsafe_op_in_unsafe_fn_deref_raw_pointer_requires_unsafe =
+ dereference of raw pointer is unsafe and requires unsafe block (error E0133)
+ .note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+ .label = dereference of raw pointer
+
+mir_build_unsafe_op_in_unsafe_fn_extern_static_requires_unsafe =
+ use of extern static is unsafe and requires unsafe block (error E0133)
+ .note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+ .label = use of extern static
+
+mir_build_unsafe_op_in_unsafe_fn_initializing_type_with_requires_unsafe =
+ initializing type with `rustc_layout_scalar_valid_range` attr is unsafe and requires unsafe
+ block (error E0133)
+ .note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+ .label = initializing type with `rustc_layout_scalar_valid_range` attr
+
+mir_build_unsafe_op_in_unsafe_fn_inline_assembly_requires_unsafe =
+ use of inline assembly is unsafe and requires unsafe block (error E0133)
+ .note = inline assembly is entirely unchecked and can cause undefined behavior
+ .label = use of inline assembly
+
+mir_build_unsafe_op_in_unsafe_fn_mutable_static_requires_unsafe =
+ use of mutable static is unsafe and requires unsafe block (error E0133)
+ .note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
+ .label = use of mutable static
+
+mir_build_unsafe_op_in_unsafe_fn_mutation_of_layout_constrained_field_requires_unsafe =
+ mutation of layout constrained field is unsafe and requires unsafe block (error E0133)
+ .note = mutating layout constrained fields cannot statically be checked for valid values
+ .label = mutation of layout constrained field
+
+mir_build_unsafe_op_in_unsafe_fn_union_field_requires_unsafe =
+ access to union field is unsafe and requires unsafe block (error E0133)
+ .note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+ .label = access to union field
+
+mir_build_unsized_pattern = cannot use unsized non-slice type `{$non_sm_ty}` in constant patterns
+
+mir_build_unused_unsafe = unnecessary `unsafe` block
+ .label = unnecessary `unsafe` block
+
+mir_build_unused_unsafe_enclosing_block_label = because it's nested under this `unsafe` block
+mir_build_unused_unsafe_enclosing_fn_label = because it's nested under this `unsafe` fn
+
+mir_build_variant_defined_here = not covered
diff --git a/compiler/rustc_mir_build/src/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs
index 609ab1928..ab4cd2488 100644
--- a/compiler/rustc_mir_build/src/build/block.rs
+++ b/compiler/rustc_mir_build/src/build/block.rs
@@ -351,7 +351,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
let popped = this.block_context.pop();
- assert!(popped.map_or(false, |bf| bf.is_statement()));
+ assert!(popped.is_some_and(|bf| bf.is_statement()));
}
// Then, the block may have an optional trailing expression which is a “return” value
@@ -367,7 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
unpack!(block = this.expr_into_dest(destination, block, expr));
let popped = this.block_context.pop();
- assert!(popped.map_or(false, |bf| bf.is_tail_expr()));
+ assert!(popped.is_some_and(|bf| bf.is_tail_expr()));
} else {
// If a block has no trailing expression, then it is given an implicit return type.
// This return type is usually `()`, unless the block is diverging, in which case the
diff --git a/compiler/rustc_mir_build/src/build/custom/mod.rs b/compiler/rustc_mir_build/src/build/custom/mod.rs
index d385153ba..32c618828 100644
--- a/compiler/rustc_mir_build/src/build/custom/mod.rs
+++ b/compiler/rustc_mir_build/src/build/custom/mod.rs
@@ -21,7 +21,7 @@ use rustc_ast::Attribute;
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::def_id::DefId;
use rustc_hir::HirId;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::{
mir::*,
thir::*,
diff --git a/compiler/rustc_mir_build/src/build/custom/parse.rs b/compiler/rustc_mir_build/src/build/custom/parse.rs
index 12b2f5d80..803207d9d 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse.rs
@@ -1,4 +1,4 @@
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::{mir::*, thir::*, ty::Ty};
use rustc_span::Span;
diff --git a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
index 931fe1b24..ebf830cb9 100644
--- a/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
+++ b/compiler/rustc_mir_build/src/build/custom/parse/instruction.rs
@@ -57,6 +57,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
place: self.parse_place(args[0])?,
target: self.parse_block(args[1])?,
unwind: UnwindAction::Continue,
+ replace: false,
})
},
@call("mir_call", args) => {
@@ -154,6 +155,7 @@ impl<'tcx, 'body> ParseCtxt<'tcx, 'body> {
Ok(Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, offset))))
},
@call("mir_len", args) => Ok(Rvalue::Len(self.parse_place(args[0])?)),
+ @call("mir_copy_for_deref", args) => Ok(Rvalue::CopyForDeref(self.parse_place(args[0])?)),
ExprKind::Borrow { borrow_kind, arg } => Ok(
Rvalue::Ref(self.tcx.lifetimes.re_erased, *borrow_kind, self.parse_place(*arg)?)
),
diff --git a/compiler/rustc_mir_build/src/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
index 99291740a..4d99ab4b0 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_constant.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs
@@ -52,7 +52,7 @@ pub fn as_constant_inner<'tcx>(
match lit_to_mir_constant(tcx, LitToConstInput { lit: &lit.node, ty, neg }) {
Ok(c) => c,
Err(LitToConstError::Reported(guar)) => {
- ConstantKind::Ty(tcx.const_error_with_guaranteed(ty, guar))
+ ConstantKind::Ty(tcx.const_error(ty, guar))
}
Err(LitToConstError::TypeError) => {
bug!("encountered type error in `lit_to_mir_constant`")
@@ -78,7 +78,7 @@ pub fn as_constant_inner<'tcx>(
ExprKind::NamedConst { def_id, substs, ref user_ty } => {
let user_ty = user_ty.as_ref().and_then(push_cuta);
- let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval = mir::UnevaluatedConst::new(def_id, substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty, span, literal }
@@ -90,7 +90,7 @@ pub fn as_constant_inner<'tcx>(
Constant { user_ty: None, span, literal }
}
ExprKind::ConstBlock { did: def_id, substs } => {
- let uneval = mir::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval = mir::UnevaluatedConst::new(def_id, substs);
let literal = ConstantKind::Unevaluated(uneval, ty);
Constant { user_ty: None, span, literal }
@@ -146,6 +146,12 @@ pub(crate) fn lit_to_mir_constant<'tcx>(
let id = tcx.allocate_bytes(data);
ConstValue::Scalar(Scalar::from_pointer(id.into(), &tcx))
}
+ (ast::LitKind::CStr(data, _), ty::Ref(_, inner_ty, _)) if matches!(inner_ty.kind(), ty::Adt(def, _) if Some(def.did()) == tcx.lang_items().c_str()) =>
+ {
+ let allocation = Allocation::from_bytes_byte_aligned_immutable(data as &[u8]);
+ let allocation = tcx.mk_const_alloc(allocation);
+ ConstValue::Slice { data: allocation, start: 0, end: data.len() }
+ }
(ast::LitKind::Byte(n), ty::Uint(ty::UintTy::U8)) => {
ConstValue::Scalar(Scalar::from_uint(*n, Size::from_bytes(1)))
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
index 6941da331..744111edb 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_operand.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_operand.rs
@@ -118,7 +118,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let category = Category::of(&expr.kind).unwrap();
debug!(?category, ?expr.kind);
match category {
- Category::Constant if let NeedsTemporary::No = needs_temporary || !expr.ty.needs_drop(this.tcx, this.param_env) => {
+ Category::Constant
+ if matches!(needs_temporary, NeedsTemporary::No)
+ || !expr.ty.needs_drop(this.tcx, this.param_env) =>
+ {
let constant = this.as_constant(expr);
block.and(Operand::Constant(Box::new(constant)))
}
@@ -126,7 +129,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let operand = unpack!(block = this.as_temp(block, scope, expr, Mutability::Mut));
// Overwrite temp local info if we have something more interesting to record.
if !matches!(local_info, LocalInfo::Boring) {
- let decl_info = this.local_decls[operand].local_info.as_mut().assert_crate_local();
+ let decl_info =
+ this.local_decls[operand].local_info.as_mut().assert_crate_local();
if let LocalInfo::Boring | LocalInfo::BlockTailTemp(_) = **decl_info {
**decl_info = local_info;
}
diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs
index fb775766c..7ec57add6 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_place.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs
@@ -557,6 +557,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ConstBlock { .. }
| ExprKind::StaticRef { .. }
| ExprKind::InlineAsm { .. }
+ | ExprKind::OffsetOf { .. }
| ExprKind::Yield { .. }
| ExprKind::ThreadLocalRef(_)
| ExprKind::Call { .. } => {
diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
index 8631749a5..3742d640e 100644
--- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
+++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
@@ -1,6 +1,6 @@
//! See docs in `build/expr/mod.rs`.
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::ty::util::IntTypeExt;
use rustc_target::abi::{Abi, FieldIdx, Primitive};
@@ -15,6 +15,7 @@ use rustc_middle::mir::Place;
use rustc_middle::mir::*;
use rustc_middle::thir::*;
use rustc_middle::ty::cast::{mir_cast_kind, CastTy};
+use rustc_middle::ty::layout::IntegerExt;
use rustc_middle::ty::{self, Ty, UpvarSubsts};
use rustc_span::Span;
@@ -225,49 +226,63 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
let (op,ty) = (Operand::Move(discr), discr_ty);
- if let Abi::Scalar(scalar) = layout.unwrap().abi{
- if let Primitive::Int(_, signed) = scalar.primitive() {
- let range = scalar.valid_range(&this.tcx);
- // FIXME: Handle wraparound cases too.
- if range.end >= range.start {
- let mut assumer = |range: u128, bin_op: BinOp| {
- // We will be overwriting this val if our scalar is signed value
- // because sign extension on unsigned types might cause unintended things
- let mut range_val =
- ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(discr_ty));
- let bool_ty = this.tcx.types.bool;
- if signed {
- let scalar_size_extend = scalar.size(&this.tcx).sign_extend(range);
- let discr_layout = this.tcx.layout_of(this.param_env.and(discr_ty));
- let truncated_val = discr_layout.unwrap().size.truncate(scalar_size_extend);
- range_val = ConstantKind::from_bits(
- this.tcx,
- truncated_val,
- ty::ParamEnv::empty().and(discr_ty),
- );
- }
- let lit_op = this.literal_operand(expr.span, range_val);
- let is_bin_op = this.temp(bool_ty, expr_span);
- this.cfg.push_assign(
- block,
- source_info,
- is_bin_op,
- Rvalue::BinaryOp(bin_op, Box::new(((lit_op), (Operand::Copy(discr))))),
- );
- this.cfg.push(
- block,
- Statement {
- source_info,
- kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
- Operand::Copy(is_bin_op),
- ))),
- },
- )
- };
- assumer(range.end, BinOp::Ge);
- assumer(range.start, BinOp::Le);
- }
- }
+ if let Abi::Scalar(scalar) = layout.unwrap().abi
+ && !scalar.is_always_valid(&this.tcx)
+ && let Primitive::Int(int_width, _signed) = scalar.primitive()
+ {
+ let unsigned_ty = int_width.to_ty(this.tcx, false);
+ let unsigned_place = this.temp(unsigned_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ unsigned_place,
+ Rvalue::Cast(CastKind::IntToInt, Operand::Copy(discr), unsigned_ty));
+
+ let bool_ty = this.tcx.types.bool;
+ let range = scalar.valid_range(&this.tcx);
+ let merge_op =
+ if range.start <= range.end {
+ BinOp::BitAnd
+ } else {
+ BinOp::BitOr
+ };
+
+ let mut comparer = |range: u128, bin_op: BinOp| -> Place<'tcx> {
+ let range_val =
+ ConstantKind::from_bits(this.tcx, range, ty::ParamEnv::empty().and(unsigned_ty));
+ let lit_op = this.literal_operand(expr.span, range_val);
+ let is_bin_op = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ is_bin_op,
+ Rvalue::BinaryOp(bin_op, Box::new((Operand::Copy(unsigned_place), lit_op))),
+ );
+ is_bin_op
+ };
+ let assert_place = if range.start == 0 {
+ comparer(range.end, BinOp::Le)
+ } else {
+ let start_place = comparer(range.start, BinOp::Ge);
+ let end_place = comparer(range.end, BinOp::Le);
+ let merge_place = this.temp(bool_ty, expr_span);
+ this.cfg.push_assign(
+ block,
+ source_info,
+ merge_place,
+ Rvalue::BinaryOp(merge_op, Box::new((Operand::Move(start_place), Operand::Move(end_place)))),
+ );
+ merge_place
+ };
+ this.cfg.push(
+ block,
+ Statement {
+ source_info,
+ kind: StatementKind::Intrinsic(Box::new(NonDivergingIntrinsic::Assume(
+ Operand::Move(assert_place),
+ ))),
+ },
+ );
}
(op,ty)
@@ -481,6 +496,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}))))
}
+ ExprKind::OffsetOf { container, fields } => {
+ block.and(Rvalue::NullaryOp(NullOp::OffsetOf(fields), container))
+ }
+
ExprKind::Literal { .. }
| ExprKind::NamedConst { .. }
| ExprKind::NonHirLiteral { .. }
@@ -706,6 +725,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: to_drop,
target: success,
unwind: UnwindAction::Continue,
+ replace: false,
},
);
this.diverge_from(block);
diff --git a/compiler/rustc_mir_build/src/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs
index d33401f07..d9aa461c1 100644
--- a/compiler/rustc_mir_build/src/build/expr/category.rs
+++ b/compiler/rustc_mir_build/src/build/expr/category.rs
@@ -67,7 +67,8 @@ impl Category {
| ExprKind::Repeat { .. }
| ExprKind::Assign { .. }
| ExprKind::AssignOp { .. }
- | ExprKind::ThreadLocalRef(_) => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
+ | ExprKind::ThreadLocalRef(_)
+ | ExprKind::OffsetOf { .. } => Some(Category::Rvalue(RvalueFunc::AsRvalue)),
ExprKind::ConstBlock { .. }
| ExprKind::Literal { .. }
diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs
index 05a723a6b..29ff916d2 100644
--- a/compiler/rustc_mir_build/src/build/expr/into.rs
+++ b/compiler/rustc_mir_build/src/build/expr/into.rs
@@ -163,13 +163,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
//
// [block: If(lhs)] -true-> [else_block: dest = (rhs)]
// | (false)
- // [shortcurcuit_block: dest = false]
+ // [shortcircuit_block: dest = false]
//
// Or:
//
// [block: If(lhs)] -false-> [else_block: dest = (rhs)]
// | (true)
- // [shortcurcuit_block: dest = true]
+ // [shortcircuit_block: dest = true]
let (shortcircuit_block, mut else_block, join_block) = (
this.cfg.start_new_block(),
@@ -561,7 +561,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| ExprKind::ZstLiteral { .. }
| ExprKind::ConstParam { .. }
| ExprKind::ThreadLocalRef(_)
- | ExprKind::StaticRef { .. } => {
+ | ExprKind::StaticRef { .. }
+ | ExprKind::OffsetOf { .. } => {
debug_assert!(match Category::of(&expr.kind).unwrap() {
// should be handled above
Category::Rvalue(RvalueFunc::Into) => false,
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 4926ff85d..6df06df5c 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -2241,6 +2241,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
+ references: 0,
value: VarDebugInfoContents::Place(for_arm_body.into()),
argument_index: None,
});
@@ -2260,6 +2261,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info: debug_source_info,
+ references: 0,
value: VarDebugInfoContents::Place(ref_for_guard.into()),
argument_index: None,
});
diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs
index 8a03ea7e2..dbdb5b4a9 100644
--- a/compiler/rustc_mir_build/src/build/matches/test.rs
+++ b/compiler/rustc_mir_build/src/build/matches/test.rs
@@ -77,7 +77,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
| PatKind::Wild
| PatKind::Binding { .. }
| PatKind::Leaf { .. }
- | PatKind::Deref { .. } => self.error_simplifyable(match_pair),
+ | PatKind::Deref { .. } => self.error_simplifiable(match_pair),
}
}
@@ -173,7 +173,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert_ne!(
target_blocks[idx.index()],
otherwise_block,
- "no canididates for tested discriminant: {:?}",
+ "no candidates for tested discriminant: {:?}",
discr,
);
Some((discr.val, target_blocks[idx.index()]))
@@ -181,7 +181,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
debug_assert_eq!(
target_blocks[idx.index()],
otherwise_block,
- "found canididates for untested discriminant: {:?}",
+ "found candidates for untested discriminant: {:?}",
discr,
);
None
@@ -380,18 +380,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
);
}
- /// Compare two `&T` values using `<T as std::compare::PartialEq>::eq`
+ /// Compare two values using `<T as std::compare::PartialEq>::eq`.
+ /// If the values are already references, just call it directly, otherwise
+ /// take a reference to the values first and then call it.
fn non_scalar_compare(
&mut self,
block: BasicBlock,
make_target_blocks: impl FnOnce(&mut Self) -> Vec<BasicBlock>,
source_info: SourceInfo,
value: ConstantKind<'tcx>,
- place: Place<'tcx>,
+ mut val: Place<'tcx>,
mut ty: Ty<'tcx>,
) {
let mut expect = self.literal_operand(source_info.span, value);
- let mut val = Operand::Copy(place);
// If we're using `b"..."` as a pattern, we need to insert an
// unsizing coercion, as the byte string has the type `&[u8; N]`.
@@ -421,9 +422,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
block,
source_info,
temp,
- Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), val, ty),
+ Rvalue::Cast(
+ CastKind::Pointer(PointerCast::Unsize),
+ Operand::Copy(val),
+ ty,
+ ),
);
- val = Operand::Move(temp);
+ val = temp;
}
if opt_ref_test_ty.is_some() {
let slice = self.temp(ty, source_info.span);
@@ -438,12 +443,36 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
}
- let ty::Ref(_, deref_ty, _) = *ty.kind() else {
- bug!("non_scalar_compare called on non-reference type: {}", ty);
- };
+ match *ty.kind() {
+ ty::Ref(_, deref_ty, _) => ty = deref_ty,
+ _ => {
+ // non_scalar_compare called on non-reference type
+ let temp = self.temp(ty, source_info.span);
+ self.cfg.push_assign(block, source_info, temp, Rvalue::Use(expect));
+ let ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, ty);
+ let ref_temp = self.temp(ref_ty, source_info.span);
+
+ self.cfg.push_assign(
+ block,
+ source_info,
+ ref_temp,
+ Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, temp),
+ );
+ expect = Operand::Move(ref_temp);
+
+ let ref_temp = self.temp(ref_ty, source_info.span);
+ self.cfg.push_assign(
+ block,
+ source_info,
+ ref_temp,
+ Rvalue::Ref(self.tcx.lifetimes.re_erased, BorrowKind::Shared, val),
+ );
+ val = ref_temp;
+ }
+ }
let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
- let method = trait_method(self.tcx, eq_def_id, sym::eq, [deref_ty, deref_ty]);
+ let method = trait_method(self.tcx, eq_def_id, sym::eq, [ty, ty]);
let bool_ty = self.tcx.types.bool;
let eq_result = self.temp(bool_ty, source_info.span);
@@ -463,7 +492,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
literal: method,
})),
- args: vec![val, expect],
+ args: vec![Operand::Copy(val), expect],
destination: eq_result,
target: Some(eq_block),
unwind: UnwindAction::Continue,
@@ -499,7 +528,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
/// However, in some cases, the test may just not be relevant to candidate.
/// For example, suppose we are testing whether `foo.x == 22`, but in one
/// match arm we have `Foo { x: _, ... }`... in that case, the test for
- /// what value `x` has has no particular relevance to this candidate. In
+ /// the value of `x` has no particular relevance to this candidate. In
/// such cases, this function just returns None without doing anything.
/// This is used by the overall `match_candidates` algorithm to structure
/// the match as a whole. See `match_candidates` for more details.
@@ -763,8 +792,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
candidate.match_pairs.extend(consequent_match_pairs);
}
- fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
- span_bug!(match_pair.pattern.span, "simplifyable pattern found: {:?}", match_pair.pattern)
+ fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
+ span_bug!(match_pair.pattern.span, "simplifiable pattern found: {:?}", match_pair.pattern)
}
fn const_range_contains(
diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs
index bc50bcbc3..4e3e98b56 100644
--- a/compiler/rustc_mir_build/src/build/mod.rs
+++ b/compiler/rustc_mir_build/src/build/mod.rs
@@ -11,7 +11,7 @@ use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_hir::{GeneratorKind, Node};
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::middle::region;
@@ -32,43 +32,34 @@ use super::lints;
pub(crate) fn mir_built(
tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
) -> &rustc_data_structures::steal::Steal<Body<'_>> {
- if let Some(def) = def.try_upgrade(tcx) {
- return tcx.mir_built(def);
- }
-
- let mut body = mir_build(tcx, def);
- if def.const_param_did.is_some() {
- assert!(matches!(body.source.instance, ty::InstanceDef::Item(_)));
- body.source = MirSource::from_instance(ty::InstanceDef::Item(def.to_global()));
- }
-
- tcx.alloc_steal_mir(body)
+ tcx.alloc_steal_mir(mir_build(tcx, def))
}
/// Construct the MIR for a given `DefId`.
-fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+fn mir_build(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
// Ensure unsafeck and abstract const building is ran before we steal the THIR.
- match def {
- ty::WithOptConstParam { did, const_param_did: Some(const_param_did) } => {
- tcx.ensure_with_value().thir_check_unsafety_for_const_arg((did, const_param_did));
- tcx.ensure_with_value().thir_abstract_const_of_const_arg((did, const_param_did));
- }
- ty::WithOptConstParam { did, const_param_did: None } => {
- tcx.ensure_with_value().thir_check_unsafety(did);
- tcx.ensure_with_value().thir_abstract_const(did);
- tcx.ensure_with_value().check_match(did);
- }
+ tcx.ensure_with_value().thir_check_unsafety(def);
+ tcx.ensure_with_value().thir_abstract_const(def);
+ if let Err(e) = tcx.check_match(def) {
+ return construct_error(tcx, def, e);
}
let body = match tcx.thir_body(def) {
- Err(error_reported) => construct_error(tcx, def.did, error_reported),
+ Err(error_reported) => construct_error(tcx, def, error_reported),
Ok((thir, expr)) => {
// We ran all queries that depended on THIR at the beginning
// of `mir_build`, so now we can steal it
let thir = thir.steal();
+ tcx.ensure().check_match(def);
+ // this must run before MIR dump, because
+ // "not all control paths return a value" is reported here.
+ //
+ // maybe move the check to a MIR pass?
+ tcx.ensure().check_liveness(def);
+
match thir.body_type {
thir::BodyTy::Fn(fn_sig) => construct_fn(tcx, def, &thir, expr, fn_sig),
thir::BodyTy::Const(ty) => construct_const(tcx, def, &thir, expr, ty),
@@ -161,8 +152,7 @@ struct Builder<'a, 'tcx> {
thir: &'a Thir<'tcx>,
cfg: CFG<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
- def_id: DefId,
+ def_id: LocalDefId,
hir_id: hir::HirId,
parent_module: DefId,
check_overflow: bool,
@@ -428,26 +418,26 @@ macro_rules! unpack {
fn construct_fn<'tcx>(
tcx: TyCtxt<'tcx>,
- fn_def: ty::WithOptConstParam<LocalDefId>,
+ fn_def: LocalDefId,
thir: &Thir<'tcx>,
expr: ExprId,
fn_sig: ty::FnSig<'tcx>,
) -> Body<'tcx> {
- let span = tcx.def_span(fn_def.did);
- let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def.did);
- let generator_kind = tcx.generator_kind(fn_def.did);
+ let span = tcx.def_span(fn_def);
+ let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def);
+ let generator_kind = tcx.generator_kind(fn_def);
// The representation of thir for `-Zunpretty=thir-tree` relies on
// the entry expression being the last element of `thir.exprs`.
assert_eq!(expr.as_usize(), thir.exprs.len() - 1);
// Figure out what primary body this item has.
- let body_id = tcx.hir().body_owned_by(fn_def.did);
+ let body_id = tcx.hir().body_owned_by(fn_def);
let span_with_body = tcx.hir().span_with_body(fn_id);
let return_ty_span = tcx
.hir()
.fn_decl_by_hir_id(fn_id)
- .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def.did))
+ .unwrap_or_else(|| span_bug!(span, "can't build MIR for {:?}", fn_def))
.output
.span();
@@ -457,7 +447,7 @@ fn construct_fn<'tcx>(
};
let mut abi = fn_sig.abi;
- if let DefKind::Closure = tcx.def_kind(fn_def.did) {
+ if let DefKind::Closure = tcx.def_kind(fn_def) {
// HACK(eddyb) Avoid having RustCall on closures,
// as it adds unnecessary (and wrong) auto-tupling.
abi = Abi::Rust;
@@ -483,7 +473,7 @@ fn construct_fn<'tcx>(
{
return custom::build_custom_mir(
tcx,
- fn_def.did.to_def_id(),
+ fn_def.to_def_id(),
fn_id,
thir,
expr,
@@ -547,12 +537,12 @@ fn construct_fn<'tcx>(
fn construct_const<'a, 'tcx>(
tcx: TyCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
thir: &'a Thir<'tcx>,
expr: ExprId,
const_ty: Ty<'tcx>,
) -> Body<'tcx> {
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
// Figure out what primary body this item has.
let (span, const_ty_span) = match tcx.hir().get(hir_id) {
@@ -568,10 +558,10 @@ fn construct_const<'a, 'tcx>(
..
}) => (*span, ty.span),
Node::AnonConst(_) => {
- let span = tcx.def_span(def.did);
+ let span = tcx.def_span(def);
(span, span)
}
- _ => span_bug!(tcx.def_span(def.did), "can't build MIR for {:?}", def.did),
+ _ => span_bug!(tcx.def_span(def), "can't build MIR for {:?}", def),
};
let infcx = tcx.infer_ctxt().build();
@@ -669,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn new(
thir: &'a Thir<'tcx>,
infcx: InferCtxt<'tcx>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
hir_id: hir::HirId,
span: Span,
arg_count: usize,
@@ -688,20 +678,19 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
check_overflow |= tcx.sess.overflow_checks();
// Constants always need overflow checks.
check_overflow |= matches!(
- tcx.hir().body_owner_kind(def.did),
+ tcx.hir().body_owner_kind(def),
hir::BodyOwnerKind::Const | hir::BodyOwnerKind::Static(_)
);
let lint_level = LintLevel::Explicit(hir_id);
- let param_env = tcx.param_env(def.did);
+ let param_env = tcx.param_env(def);
let mut builder = Builder {
thir,
tcx,
infcx,
- region_scope_tree: tcx.region_scope_tree(def.did),
+ region_scope_tree: tcx.region_scope_tree(def),
param_env,
- def,
- def_id: def.did.to_def_id(),
+ def_id: def,
hir_id,
parent_module: tcx.parent_module(hir_id).to_def_id(),
check_overflow,
@@ -741,7 +730,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
Body::new(
- MirSource::item(self.def_id),
+ MirSource::item(self.def_id.to_def_id()),
self.cfg.basic_blocks,
self.source_scopes,
self.local_decls,
@@ -779,7 +768,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
let tcx = self.tcx;
self.upvars = tcx
- .closure_captures(self.def.did)
+ .closure_captures(self.def_id)
.iter()
.zip(capture_tys)
.enumerate()
@@ -809,6 +798,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
};
self.var_debug_info.push(VarDebugInfo {
name,
+ references: 0,
source_info: SourceInfo::outermost(captured_place.var_ident.span),
value: VarDebugInfoContents::Place(use_place),
argument_index: None,
@@ -839,6 +829,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
self.var_debug_info.push(VarDebugInfo {
name,
source_info,
+ references: 0,
value: VarDebugInfoContents::Place(arg_local.into()),
argument_index: Some(argument_index as u16 + 1),
});
diff --git a/compiler/rustc_mir_build/src/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs
index f32d2db4e..7c0fbc6f8 100644
--- a/compiler/rustc_mir_build/src/build/scope.rs
+++ b/compiler/rustc_mir_build/src/build/scope.rs
@@ -86,12 +86,12 @@ use std::mem;
use crate::build::{BlockAnd, BlockAndExtension, BlockFrame, Builder, CFG};
use rustc_data_structures::fx::FxHashMap;
use rustc_hir::HirId;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::middle::region;
use rustc_middle::mir::*;
use rustc_middle::thir::{Expr, LintLevel};
-use rustc_span::{DesugaringKind, Span, DUMMY_SP};
+use rustc_span::{Span, DUMMY_SP};
#[derive(Debug)]
pub struct Scopes<'tcx> {
@@ -325,10 +325,10 @@ impl DropTree {
entry_points.sort();
for (drop_idx, drop_data) in self.drops.iter_enumerated().rev() {
- if entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+ if entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
let block = *blocks[drop_idx].get_or_insert_with(|| T::make_block(cfg));
needs_block[drop_idx] = Block::Own;
- while entry_points.last().map_or(false, |entry_point| entry_point.0 == drop_idx) {
+ while entry_points.last().is_some_and(|entry_point| entry_point.0 == drop_idx) {
let entry_block = entry_points.pop().unwrap().1;
T::add_entry(cfg, entry_block, block);
}
@@ -371,6 +371,7 @@ impl DropTree {
// The caller will handle this if needed.
unwind: UnwindAction::Terminate,
place: drop_data.0.local.into(),
+ replace: false,
};
cfg.terminate(block, drop_data.0.source_info, terminator);
}
@@ -644,24 +645,27 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}
};
- if let Some(destination) = destination {
- if let Some(value) = value {
+ match (destination, value) {
+ (Some(destination), Some(value)) => {
debug!("stmt_expr Break val block_context.push(SubExpr)");
self.block_context.push(BlockFrame::SubExpr);
unpack!(block = self.expr_into_dest(destination, block, value));
self.block_context.pop();
- } else {
+ }
+ (Some(destination), None) => {
self.cfg.push_assign_unit(block, source_info, destination, self.tcx)
}
- } else {
- assert!(value.is_none(), "`return` and `break` should have a destination");
- if self.tcx.sess.instrument_coverage() {
+ (None, Some(_)) => {
+ panic!("`return`, `become` and `break` with value and must have a destination")
+ }
+ (None, None) if self.tcx.sess.instrument_coverage() => {
// Unlike `break` and `return`, which push an `Assign` statement to MIR, from which
// a Coverage code region can be generated, `continue` needs no `Assign`; but
// without one, the `InstrumentCoverage` MIR pass cannot generate a code region for
// `continue`. Coverage will be missing unless we add a dummy `Assign` to MIR.
self.add_dummy_assignment(span, block, source_info);
}
+ (None, None) => {}
}
let region_scope = self.scopes.breakable_scopes[break_index].region_scope;
@@ -671,12 +675,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
} else {
self.scopes.breakable_scopes[break_index].continue_drops.as_mut().unwrap()
};
- let mut drop_idx = ROOT_NODE;
- for scope in &self.scopes.scopes[scope_index + 1..] {
- for drop in &scope.drops {
- drop_idx = drops.add_drop(*drop, drop_idx);
- }
- }
+
+ let drop_idx = self.scopes.scopes[scope_index + 1..]
+ .iter()
+ .flat_map(|scope| &scope.drops)
+ .fold(ROOT_NODE, |drop_idx, &drop| drops.add_drop(drop, drop_idx));
+
drops.add_entry(block, drop_idx);
// `build_drop_trees` doesn't have access to our source_info, so we
@@ -728,7 +732,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
fn leave_top_scope(&mut self, block: BasicBlock) -> BasicBlock {
// If we are emitting a `drop` statement, we need to have the cached
// diverge cleanup pads ready in case that drop panics.
- let needs_cleanup = self.scopes.scopes.last().map_or(false, |scope| scope.needs_cleanup());
+ let needs_cleanup = self.scopes.scopes.last().is_some_and(|scope| scope.needs_cleanup());
let is_generator = self.generator_kind.is_some();
let unwind_to = if needs_cleanup { self.diverge_cleanup() } else { DropIdx::MAX };
@@ -1125,9 +1129,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place: Place<'tcx>,
value: Rvalue<'tcx>,
) -> BlockAnd<()> {
- let span = self.tcx.with_stable_hashing_context(|hcx| {
- span.mark_with_reason(None, DesugaringKind::Replace, self.tcx.sess.edition(), hcx)
- });
let source_info = self.source_info(span);
// create the new block for the assignment
@@ -1145,6 +1146,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
place,
target: assign,
unwind: UnwindAction::Cleanup(assign_unwind),
+ replace: true,
},
);
self.diverge_from(block);
@@ -1172,7 +1174,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
TerminatorKind::Assert {
cond,
expected,
- msg,
+ msg: Box::new(msg),
target: success_block,
unwind: UnwindAction::Continue,
},
@@ -1258,6 +1260,7 @@ fn build_scope_drops<'tcx>(
place: local.into(),
target: next,
unwind: UnwindAction::Continue,
+ replace: false,
},
);
block = next;
diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs
index 03a7f2d70..0506f2bf2 100644
--- a/compiler/rustc_mir_build/src/check_unsafety.rs
+++ b/compiler/rustc_mir_build/src/check_unsafety.rs
@@ -117,10 +117,10 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> {
}
/// Handle closures/generators/inline-consts, which is unsafecked with their parent body.
- fn visit_inner_body(&mut self, def: ty::WithOptConstParam<LocalDefId>) {
+ fn visit_inner_body(&mut self, def: LocalDefId) {
if let Ok((inner_thir, expr)) = self.tcx.thir_body(def) {
let inner_thir = &inner_thir.borrow();
- let hir_context = self.tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_context = self.tcx.hir().local_def_id_to_hir_id(def);
let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, hir_context, ..*self };
inner_visitor.visit_expr(&inner_thir[expr]);
// Unsafe blocks can be used in the inner body, make sure to take it into account
@@ -323,6 +323,7 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
| ExprKind::Box { .. }
| ExprKind::If { .. }
| ExprKind::InlineAsm { .. }
+ | ExprKind::OffsetOf { .. }
| ExprKind::LogicalOp { .. }
| ExprKind::Use { .. } => {
// We don't need to save the old value and restore it
@@ -396,18 +397,11 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for UnsafetyVisitor<'a, 'tcx> {
movability: _,
fake_reads: _,
}) => {
- let closure_def = if let Some((did, const_param_id)) =
- ty::WithOptConstParam::try_lookup(closure_id, self.tcx)
- {
- ty::WithOptConstParam { did, const_param_did: Some(const_param_id) }
- } else {
- ty::WithOptConstParam::unknown(closure_id)
- };
- self.visit_inner_body(closure_def);
+ self.visit_inner_body(closure_id);
}
ExprKind::ConstBlock { did, substs: _ } => {
let def_id = did.expect_local();
- self.visit_inner_body(ty::WithOptConstParam::unknown(def_id));
+ self.visit_inner_body(def_id);
}
ExprKind::Field { lhs, .. } => {
let lhs = &self.thir[lhs];
@@ -706,14 +700,14 @@ impl UnsafeOpKind {
}
}
-pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
+pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) {
// THIR unsafeck is gated under `-Z thir-unsafeck`
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
return;
}
// Closures and inline consts are handled by their owner, if it has a body
- if tcx.is_typeck_child(def.did.to_def_id()) {
+ if tcx.is_typeck_child(def.to_def_id()) {
return;
}
@@ -726,7 +720,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
return;
}
- let hir_id = tcx.hir().local_def_id_to_hir_id(def.did);
+ let hir_id = tcx.hir().local_def_id_to_hir_id(def);
let body_unsafety = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(BodyUnsafety::Safe, |fn_sig| {
if fn_sig.header.unsafety == hir::Unsafety::Unsafe {
BodyUnsafety::Unsafe(fn_sig.span)
@@ -734,7 +728,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
BodyUnsafety::Safe
}
});
- let body_target_features = &tcx.body_codegen_attrs(def.did.to_def_id()).target_features;
+ let body_target_features = &tcx.body_codegen_attrs(def.to_def_id()).target_features;
let safety_context =
if body_unsafety.is_unsafe() { SafetyContext::UnsafeFn } else { SafetyContext::Safe };
let mut visitor = UnsafetyVisitor {
@@ -746,23 +740,8 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) {
body_target_features,
assignment_info: None,
in_union_destructure: false,
- param_env: tcx.param_env(def.did),
+ param_env: tcx.param_env(def),
inside_adt: false,
};
visitor.visit_expr(&thir[expr]);
}
-
-pub(crate) fn thir_check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.thir_check_unsafety_for_const_arg(def)
- } else {
- check_unsafety(tcx, ty::WithOptConstParam::unknown(def_id))
- }
-}
-
-pub(crate) fn thir_check_unsafety_for_const_arg(
- tcx: TyCtxt<'_>,
- (did, param_did): (LocalDefId, DefId),
-) {
- check_unsafety(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
-}
diff --git a/compiler/rustc_mir_build/src/errors.rs b/compiler/rustc_mir_build/src/errors.rs
index 43e787db4..7c0df201b 100644
--- a/compiler/rustc_mir_build/src/errors.rs
+++ b/compiler/rustc_mir_build/src/errors.rs
@@ -384,13 +384,8 @@ impl<'a> IntoDiagnostic<'a> for NonExhaustivePatternsTypeNotEmpty<'_, '_, '_> {
diag.span_note(span, fluent::mir_build_def_note);
}
- let is_variant_list_non_exhaustive = match self.ty.kind() {
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => {
- true
- }
- _ => false,
- };
-
+ let is_variant_list_non_exhaustive = matches!(self.ty.kind(),
+ ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
if is_variant_list_non_exhaustive {
diag.note(fluent::mir_build_non_exhaustive_type_note);
} else {
@@ -786,6 +781,8 @@ pub(crate) struct PatternNotCovered<'s, 'tcx> {
pub interpreted_as_const: Option<InterpretedAsConst>,
#[subdiagnostic]
pub adt_defined_here: Option<AdtDefinedHere<'tcx>>,
+ #[note(mir_build_privately_uninhabited)]
+ pub witness_1_is_privately_uninhabited: Option<()>,
#[note(mir_build_pattern_ty)]
pub _p: (),
pub pattern_ty: Ty<'tcx>,
diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs
index 3f9236c9d..c964e62c9 100644
--- a/compiler/rustc_mir_build/src/lib.rs
+++ b/compiler/rustc_mir_build/src/lib.rs
@@ -22,10 +22,10 @@ mod errors;
mod lints;
pub mod thir;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
fluent_messages! { "../messages.ftl" }
@@ -35,7 +35,6 @@ pub fn provide(providers: &mut Providers) {
providers.lit_to_mir_constant = build::lit_to_mir_constant;
providers.mir_built = build::mir_built;
providers.thir_check_unsafety = check_unsafety::thir_check_unsafety;
- providers.thir_check_unsafety_for_const_arg = check_unsafety::thir_check_unsafety_for_const_arg;
providers.thir_body = thir::cx::thir_body;
providers.thir_tree = thir::print::thir_tree;
providers.thir_flat = thir::print::thir_flat;
diff --git a/compiler/rustc_mir_build/src/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs
index 8aacec53f..a46ad6423 100644
--- a/compiler/rustc_mir_build/src/thir/cx/block.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/block.rs
@@ -5,7 +5,7 @@ use rustc_middle::middle::region;
use rustc_middle::thir::*;
use rustc_middle::ty;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::ty::CanonicalUserTypeAnnotation;
impl<'tcx> Cx<'tcx> {
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 8e2e92e6f..b20495d60 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -5,7 +5,7 @@ use crate::thir::util::UserAnnotatedTyHelpers;
use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir as hir;
use rustc_hir::def::{CtorKind, CtorOf, DefKind, Res};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::hir::place::Place as HirPlace;
use rustc_middle::hir::place::PlaceBase as HirPlaceBase;
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
@@ -130,6 +130,7 @@ impl<'tcx> Cx<'tcx> {
ExprKind::Pointer { cast: PointerCast::Unsize, source: self.thir.exprs.push(expr) }
}
Adjust::Pointer(cast) => ExprKind::Pointer { cast, source: self.thir.exprs.push(expr) },
+ Adjust::NeverToAny if adjustment.target.is_never() => return expr,
Adjust::NeverToAny => ExprKind::NeverToAny { source: self.thir.exprs.push(expr) },
Adjust::Deref(None) => {
adjust_span(&mut expr);
@@ -332,7 +333,7 @@ impl<'tcx> Cx<'tcx> {
} else if let Some(box_item) = tcx.lang_items().owned_box() {
if let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, fn_path)) = fun.kind
&& let hir::TyKind::Path(hir::QPath::Resolved(_, path)) = ty.kind
- && path.res.opt_def_id().map_or(false, |did| did == box_item)
+ && path.res.opt_def_id().is_some_and(|did| did == box_item)
&& fn_path.ident.name == sym::new
&& let [value] = args
{
@@ -664,6 +665,14 @@ impl<'tcx> Cx<'tcx> {
line_spans: asm.line_spans,
})),
+ hir::ExprKind::OffsetOf(_, _) => {
+ let data = self.typeck_results.offset_of_data();
+ let &(container, ref indices) = data.get(expr.hir_id).unwrap();
+ let fields = tcx.mk_fields_from_iter(indices.iter().copied());
+
+ ExprKind::OffsetOf { container, fields }
+ }
+
hir::ExprKind::ConstBlock(ref anon_const) => {
let ty = self.typeck_results().node_type(anon_const.hir_id);
let did = anon_const.def_id.to_def_id();
@@ -947,7 +956,7 @@ impl<'tcx> Cx<'tcx> {
let is_upvar = self
.tcx
.upvars_mentioned(self.body_owner)
- .map_or(false, |upvars| upvars.contains_key(&var_hir_id));
+ .is_some_and(|upvars| upvars.contains_key(&var_hir_id));
debug!(
"convert_var({:?}): is_upvar={}, body_owner={:?}",
diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs
index 070544446..463f639de 100644
--- a/compiler/rustc_mir_build/src/thir/cx/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs
@@ -20,25 +20,25 @@ use rustc_span::Span;
pub(crate) fn thir_body(
tcx: TyCtxt<'_>,
- owner_def: ty::WithOptConstParam<LocalDefId>,
+ owner_def: LocalDefId,
) -> Result<(&Steal<Thir<'_>>, ExprId), ErrorGuaranteed> {
let hir = tcx.hir();
- let body = hir.body(hir.body_owned_by(owner_def.did));
+ let body = hir.body(hir.body_owned_by(owner_def));
let mut cx = Cx::new(tcx, owner_def);
if let Some(reported) = cx.typeck_results.tainted_by_errors {
return Err(reported);
}
let expr = cx.mirror_expr(&body.value);
- let owner_id = hir.local_def_id_to_hir_id(owner_def.did);
+ let owner_id = hir.local_def_id_to_hir_id(owner_def);
if let Some(ref fn_decl) = hir.fn_decl_by_hir_id(owner_id) {
- let closure_env_param = cx.closure_env_param(owner_def.did, owner_id);
+ let closure_env_param = cx.closure_env_param(owner_def, owner_id);
let explicit_params = cx.explicit_params(owner_id, fn_decl, body);
cx.thir.params = closure_env_param.into_iter().chain(explicit_params).collect();
// The resume argument may be missing, in that case we need to provide it here.
// It will always be `()` in this case.
- if tcx.def_kind(owner_def.did) == DefKind::Generator && body.params.is_empty() {
+ if tcx.def_kind(owner_def) == DefKind::Generator && body.params.is_empty() {
cx.thir.params.push(Param {
ty: tcx.mk_unit(),
pat: None,
@@ -78,13 +78,12 @@ 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;
+ fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> {
+ let typeck_results = tcx.typeck(def);
let hir = tcx.hir();
- let hir_id = hir.local_def_id_to_hir_id(did);
+ let hir_id = hir.local_def_id_to_hir_id(def);
- let body_type = if hir.body_owner_kind(did).is_fn_or_closure() {
+ let body_type = if hir.body_owner_kind(def).is_fn_or_closure() {
// fetch the fully liberated fn signature (that is, all bound
// types/lifetimes replaced)
BodyTy::Fn(typeck_results.liberated_fn_sigs()[hir_id])
@@ -106,11 +105,11 @@ impl<'tcx> Cx<'tcx> {
Cx {
tcx,
thir: Thir::new(body_type),
- param_env: tcx.param_env(def.did),
- region_scope_tree: tcx.region_scope_tree(def.did),
+ param_env: tcx.param_env(def),
+ region_scope_tree: tcx.region_scope_tree(def),
typeck_results,
rvalue_scopes: &typeck_results.rvalue_scopes,
- body_owner: did.to_def_id(),
+ body_owner: def.to_def_id(),
adjustment_span: None,
apply_adjustments: hir
.attrs(hir_id)
diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
index 8f58db504..1e51cb9aa 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs
@@ -26,8 +26,8 @@ use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
use rustc_span::Span;
-pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
- let Ok((thir, expr)) = tcx.thir_body(ty::WithOptConstParam::unknown(def_id)) else { return };
+pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), ErrorGuaranteed> {
+ let (thir, expr) = tcx.thir_body(def_id)?;
let thir = thir.borrow();
let pattern_arena = TypedArena::default();
let mut visitor = MatchVisitor {
@@ -37,13 +37,16 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) {
lint_level: tcx.hir().local_def_id_to_hir_id(def_id),
let_source: LetSource::None,
pattern_arena: &pattern_arena,
+ error: Ok(()),
};
visitor.visit_expr(&thir[expr]);
+
for param in thir.params.iter() {
if let Some(box ref pattern) = param.pat {
visitor.check_irrefutable(pattern, "function argument", None);
}
}
+ visitor.error
}
fn create_e0004(
@@ -77,6 +80,7 @@ struct MatchVisitor<'a, 'p, 'tcx> {
lint_level: HirId,
let_source: LetSource,
pattern_arena: &'p TypedArena<DeconstructedPat<'p, 'tcx>>,
+ error: Result<(), ErrorGuaranteed>,
}
impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
@@ -86,35 +90,34 @@ impl<'a, 'tcx> Visitor<'a, 'tcx> for MatchVisitor<'a, '_, 'tcx> {
#[instrument(level = "trace", skip(self))]
fn visit_arm(&mut self, arm: &Arm<'tcx>) {
- match arm.guard {
- Some(Guard::If(expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.visit_expr(&this.thir[expr])
- });
- }
- Some(Guard::IfLet(ref pat, expr)) => {
- self.with_let_source(LetSource::IfLetGuard, |this| {
- this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
- this.visit_pat(pat);
- this.visit_expr(&this.thir[expr]);
- });
+ self.with_lint_level(arm.lint_level, |this| {
+ match arm.guard {
+ Some(Guard::If(expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.visit_expr(&this.thir[expr])
+ });
+ }
+ Some(Guard::IfLet(ref pat, expr)) => {
+ this.with_let_source(LetSource::IfLetGuard, |this| {
+ this.check_let(pat, expr, LetSource::IfLetGuard, pat.span);
+ this.visit_pat(pat);
+ this.visit_expr(&this.thir[expr]);
+ });
+ }
+ None => {}
}
- None => {}
- }
- self.visit_pat(&arm.pattern);
- self.visit_expr(&self.thir[arm.body]);
+ this.visit_pat(&arm.pattern);
+ this.visit_expr(&self.thir[arm.body]);
+ });
}
#[instrument(level = "trace", skip(self))]
fn visit_expr(&mut self, ex: &Expr<'tcx>) {
match ex.kind {
ExprKind::Scope { value, lint_level, .. } => {
- let old_lint_level = self.lint_level;
- if let LintLevel::Explicit(hir_id) = lint_level {
- self.lint_level = hir_id;
- }
- self.visit_expr(&self.thir[value]);
- self.lint_level = old_lint_level;
+ self.with_lint_level(lint_level, |this| {
+ this.visit_expr(&this.thir[value]);
+ });
return;
}
ExprKind::If { cond, then, else_opt, if_then_scope: _ } => {
@@ -186,6 +189,17 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
self.let_source = old_let_source;
}
+ fn with_lint_level(&mut self, new_lint_level: LintLevel, f: impl FnOnce(&mut Self)) {
+ if let LintLevel::Explicit(hir_id) = new_lint_level {
+ let old_lint_level = self.lint_level;
+ self.lint_level = hir_id;
+ f(self);
+ self.lint_level = old_lint_level;
+ } else {
+ f(self);
+ }
+ }
+
fn check_patterns(&self, pat: &Pat<'tcx>, rf: RefutableFlag) {
pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat));
check_for_bindings_named_same_as_variants(self, pat, rf);
@@ -232,7 +246,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
for &arm in arms {
// Check the arm for some things unrelated to exhaustiveness.
let arm = &self.thir.arms[arm];
- self.check_patterns(&arm.pattern, Refutable);
+ self.with_lint_level(arm.lint_level, |this| {
+ this.check_patterns(&arm.pattern, Refutable);
+ });
}
let tarms: Vec<_> = arms
@@ -276,9 +292,9 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
let [pat_field] = &subpatterns[..] else { bug!() };
self.check_irrefutable(&pat_field.pattern, "`for` loop binding", None);
} else {
- non_exhaustive_match(
+ self.error = Err(non_exhaustive_match(
&cx, self.thir, scrut_ty, scrut.span, witnesses, arms, expr_span,
- );
+ ));
}
}
}
@@ -406,7 +422,7 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
}
#[instrument(level = "trace", skip(self))]
- fn check_irrefutable(&self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
+ fn check_irrefutable(&mut self, pat: &Pat<'tcx>, origin: &str, sp: Option<Span>) {
let mut cx = self.new_cx(self.lint_level, false);
let pattern = self.lower_pattern(&mut cx, pat);
@@ -475,18 +491,36 @@ impl<'p, 'tcx> MatchVisitor<'_, 'p, 'tcx> {
AdtDefinedHere { adt_def_span, ty, variants }
};
- self.tcx.sess.emit_err(PatternNotCovered {
+ // Emit an extra note if the first uncovered witness would be uninhabited
+ // if we disregard visibility.
+ let witness_1_is_privately_uninhabited =
+ if cx.tcx.features().exhaustive_patterns
+ && let Some(witness_1) = witnesses.get(0)
+ && let ty::Adt(adt, substs) = witness_1.ty().kind()
+ && adt.is_enum()
+ && let Constructor::Variant(variant_index) = witness_1.ctor()
+ {
+ let variant = adt.variant(*variant_index);
+ let inhabited = variant.inhabited_predicate(cx.tcx, *adt).subst(cx.tcx, substs);
+ assert!(inhabited.apply(cx.tcx, cx.param_env, cx.module));
+ !inhabited.apply_ignore_module(cx.tcx, cx.param_env)
+ } else {
+ false
+ };
+
+ self.error = Err(self.tcx.sess.emit_err(PatternNotCovered {
span: pat.span,
origin,
uncovered: Uncovered::new(pat.span, &cx, witnesses),
inform,
interpreted_as_const,
+ witness_1_is_privately_uninhabited: witness_1_is_privately_uninhabited.then_some(()),
_p: (),
pattern_ty,
let_suggestion,
misc_suggestion,
adt_defined_here,
- });
+ }));
}
}
@@ -628,7 +662,7 @@ fn non_exhaustive_match<'p, 'tcx>(
witnesses: Vec<DeconstructedPat<'p, 'tcx>>,
arms: &[ArmId],
expr_span: Span,
-) {
+) -> ErrorGuaranteed {
let is_empty_match = arms.is_empty();
let non_empty_enum = match scrut_ty.kind() {
ty::Adt(def, _) => def.is_enum() && !def.variants().is_empty(),
@@ -640,13 +674,12 @@ fn non_exhaustive_match<'p, 'tcx>(
let pattern;
let patterns_len;
if is_empty_match && !non_empty_enum {
- cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
+ return cx.tcx.sess.emit_err(NonExhaustivePatternsTypeNotEmpty {
cx,
expr_span,
span: sp,
ty: scrut_ty,
});
- return;
} else {
// FIXME: migration of this diagnostic will require list support
let joined_patterns = joined_uncovered_patterns(cx, &witnesses);
@@ -668,13 +701,11 @@ fn non_exhaustive_match<'p, 'tcx>(
};
};
- let is_variant_list_non_exhaustive = match scrut_ty.kind() {
- ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local() => true,
- _ => false,
- };
+ let is_variant_list_non_exhaustive = matches!(scrut_ty.kind(),
+ ty::Adt(def, _) if def.is_variant_list_non_exhaustive() && !def.did().is_local());
adt_defined_here(cx, &mut err, scrut_ty, &witnesses);
- err.note(&format!(
+ err.note(format!(
"the matched value is of type `{}`{}",
scrut_ty,
if is_variant_list_non_exhaustive { ", which is marked as non-exhaustive" } else { "" }
@@ -684,13 +715,13 @@ fn non_exhaustive_match<'p, 'tcx>(
&& witnesses.len() == 1
&& matches!(witnesses[0].ctor(), Constructor::NonExhaustive)
{
- err.note(&format!(
+ err.note(format!(
"`{}` does not have a fixed maximum value, so a wildcard `_` is necessary to match \
exhaustively",
scrut_ty,
));
if cx.tcx.sess.is_nightly_build() {
- err.help(&format!(
+ err.help(format!(
"add `#![feature(precise_pointer_size_matching)]` to the crate attributes to \
enable precise `{}` matching",
scrut_ty,
@@ -795,11 +826,11 @@ fn non_exhaustive_match<'p, 'tcx>(
},
);
if let Some((span, sugg)) = suggestion {
- err.span_suggestion_verbose(span, &msg, sugg, Applicability::HasPlaceholders);
+ err.span_suggestion_verbose(span, msg, sugg, Applicability::HasPlaceholders);
} else {
- err.help(&msg);
+ err.help(msg);
}
- err.emit();
+ err.emit()
}
pub(crate) fn joined_uncovered_patterns<'p, 'tcx>(
@@ -859,7 +890,7 @@ fn adt_defined_here<'p, 'tcx>(
for pat in spans {
span.push_span_label(pat, "not covered");
}
- err.span_note(span, &format!("`{}` defined here", ty));
+ err.span_note(span, format!("`{}` defined here", ty));
}
}
diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
index 32d0404bd..b243f1dc8 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs
@@ -1,5 +1,5 @@
use rustc_hir as hir;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_infer::infer::{InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::Obligation;
use rustc_middle::mir;
@@ -62,21 +62,13 @@ struct ConstToPat<'tcx> {
treat_byte_string_as_slice: bool,
}
-mod fallback_to_const_ref {
- #[derive(Debug)]
- /// This error type signals that we encountered a non-struct-eq situation behind a reference.
- /// We bubble this up in order to get back to the reference destructuring and make that emit
- /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
- /// on such patterns (since that function takes a reference) and not have to jump through any
- /// hoops to get a reference to the value.
- pub(super) struct FallbackToConstRef(());
-
- pub(super) fn fallback_to_const_ref(c2p: &super::ConstToPat<'_>) -> FallbackToConstRef {
- assert!(c2p.behind_reference.get());
- FallbackToConstRef(())
- }
-}
-use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef};
+/// This error type signals that we encountered a non-struct-eq situation.
+/// We bubble this up in order to get back to the reference destructuring and make that emit
+/// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq`
+/// on such patterns (since that function takes a reference) and not have to jump through any
+/// hoops to get a reference to the value.
+#[derive(Debug)]
+struct FallbackToConstRef;
impl<'tcx> ConstToPat<'tcx> {
fn new(
@@ -156,7 +148,7 @@ impl<'tcx> ConstToPat<'tcx> {
if let Some(non_sm_ty) = structural {
if !self.type_may_have_partial_eq_impl(cv.ty()) {
- // fatal avoids ICE from resolution of non-existent method (rare case).
+ // fatal avoids ICE from resolution of nonexistent method (rare case).
self.tcx()
.sess
.emit_fatal(TypeNotStructural { span: self.span, non_sm_ty: non_sm_ty });
@@ -191,7 +183,7 @@ impl<'tcx> ConstToPat<'tcx> {
self.tcx(),
ObligationCause::dummy(),
self.param_env,
- self.tcx().mk_trait_ref(partial_eq_trait_id, [ty, ty]),
+ ty::TraitRef::new(self.tcx(), partial_eq_trait_id, [ty, ty]),
);
// FIXME: should this call a `predicate_must_hold` variant instead?
@@ -236,13 +228,13 @@ impl<'tcx> ConstToPat<'tcx> {
let kind = match cv.ty().kind() {
ty::Float(_) => {
- tcx.emit_spanned_lint(
- lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
- id,
- span,
- FloatPattern,
- );
- PatKind::Constant { value: cv }
+ tcx.emit_spanned_lint(
+ lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN,
+ id,
+ span,
+ FloatPattern,
+ );
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if adt_def.is_union() => {
// Matching on union fields is unsafe, we can't hide it in constants
@@ -289,7 +281,7 @@ impl<'tcx> ConstToPat<'tcx> {
// Since we are behind a reference, we can just bubble the error up so we get a
// constant at reference type, making it easy to let the fallback call
// `PartialEq::eq` on it.
- return Err(fallback_to_const_ref(self));
+ return Err(FallbackToConstRef);
}
ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty()) => {
debug!(
@@ -393,11 +385,11 @@ impl<'tcx> ConstToPat<'tcx> {
self.behind_reference.set(old);
val
}
- // Backwards compatibility hack: support references to non-structural types.
- // We'll lower
- // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a
- // reference. This makes the rest of the matching logic simpler as it doesn't have
- // to figure out how to get a reference again.
+ // Backwards compatibility hack: support references to non-structural types,
+ // but hard error if we aren't behind a double reference. We could just use
+ // the fallback code path below, but that would allow *more* of this fishy
+ // code to compile, as then it only goes through the future incompat lint
+ // instead of a hard error.
ty::Adt(_, _) if !self.type_marked_structural(*pointee_ty) => {
if self.behind_reference.get() {
if !self.saw_const_match_error.get()
@@ -411,7 +403,7 @@ impl<'tcx> ConstToPat<'tcx> {
IndirectStructuralMatch { non_sm_ty: *pointee_ty },
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
} else {
if !self.saw_const_match_error.get() {
self.saw_const_match_error.set(true);
@@ -435,16 +427,9 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Wild
} else {
let old = self.behind_reference.replace(true);
- // In case there are structural-match violations somewhere in this subpattern,
- // we fall back to a const pattern. If we do not do this, we may end up with
- // a !structural-match constant that is not of reference type, which makes it
- // very hard to invoke `PartialEq::eq` on it as a fallback.
- let val = match self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false) {
- Ok(subpattern) => PatKind::Deref { subpattern },
- Err(_) => PatKind::Constant { value: cv },
- };
+ let subpattern = self.recur(tcx.deref_mir_constant(self.param_env.and(cv)), false)?;
self.behind_reference.set(old);
- val
+ PatKind::Deref { subpattern }
}
}
},
@@ -452,7 +437,7 @@ impl<'tcx> ConstToPat<'tcx> {
PatKind::Constant { value: cv }
}
ty::RawPtr(pointee) if pointee.ty.is_sized(tcx, param_env) => {
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
// FIXME: these can have very surprising behaviour where optimization levels or other
// compilation choices change the runtime behaviour of the match.
@@ -469,7 +454,7 @@ impl<'tcx> ConstToPat<'tcx> {
PointerPattern
);
}
- PatKind::Constant { value: cv }
+ return Err(FallbackToConstRef);
}
_ => {
self.saw_const_match_error.set(true);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 7c2919644..6a7714613 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -52,7 +52,7 @@ use smallvec::{smallvec, SmallVec};
use rustc_data_structures::captures::Captures;
use rustc_hir::{HirId, RangeEnd};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir;
use rustc_middle::thir::{FieldPat, Pat, PatKind, PatRange};
use rustc_middle::ty::layout::IntegerExt;
@@ -844,8 +844,8 @@ impl<'tcx> Constructor<'tcx> {
}
/// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is
- /// assumed to be built from `matrix.head_ctors()` with wildcards filtered out, and `self` is
- /// assumed to have been split from a wildcard.
+ /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out,
+ /// and `self` is assumed to have been split from a wildcard.
fn is_covered_by_any<'p>(
&self,
pcx: &PatCtxt<'_, 'p, 'tcx>,
@@ -894,7 +894,7 @@ impl<'tcx> Constructor<'tcx> {
/// in `to_ctors`: in some cases we only return `Missing`.
#[derive(Debug)]
pub(super) struct SplitWildcard<'tcx> {
- /// Constructors seen in the matrix.
+ /// Constructors (other than wildcards and opaques) seen in the matrix.
matrix_ctors: Vec<Constructor<'tcx>>,
/// All the constructors for this type
all_ctors: SmallVec<[Constructor<'tcx>; 1]>,
@@ -1037,7 +1037,7 @@ impl<'tcx> SplitWildcard<'tcx> {
// Since `all_ctors` never contains wildcards, this won't recurse further.
self.all_ctors =
self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect();
- self.matrix_ctors = ctors.filter(|c| !c.is_wildcard()).cloned().collect();
+ self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect();
}
/// Whether there are any value constructors for this type that are not present in the matrix.
diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
index 70d015a39..1cf2f7ec0 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs
@@ -16,7 +16,7 @@ use rustc_hir as hir;
use rustc_hir::def::{CtorOf, DefKind, Res};
use rustc_hir::pat_util::EnumerateAndAdjustIterator;
use rustc_hir::RangeEnd;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::interpret::{
ConstValue, ErrorHandled, LitToConstError, LitToConstInput, Scalar,
};
@@ -229,7 +229,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> {
self.lower_pattern_range(ty, lc, hc, end, lo_span, lo_expr, hi_expr)
}
None => {
- let msg = &format!(
+ let msg = format!(
"found bad range pattern `{:?}` outside of error recovery",
(&lo, &hi),
);
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index d8f66a175..e5b635069 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -288,6 +288,22 @@
//!
//! The details are not necessary to understand this file, so we explain them in
//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function.
+//!
+//! # Constants in patterns
+//!
+//! There are two kinds of constants in patterns:
+//!
+//! * literals (`1`, `true`, `"foo"`)
+//! * named or inline consts (`FOO`, `const { 5 + 6 }`)
+//!
+//! The latter are converted into other patterns with literals at the leaves. For example
+//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])`
+//! pattern. This gets problematic when comparing the constant via `==` would behave differently
+//! from matching on the constant converted to a pattern. Situations like that can occur, when
+//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different.
+//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually
+//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate
+//! in exhaustiveness, specialization or overlap checking.
use self::ArmType::*;
use self::Usefulness::*;
@@ -685,10 +701,9 @@ enum ArmType {
/// For example, if we are constructing a witness for the match against
///
/// ```compile_fail,E0004
-/// # #![feature(type_ascription)]
/// struct Pair(Option<(u32, u32)>, bool);
/// # fn foo(p: Pair) {
-/// match (p: Pair) {
+/// match p {
/// Pair(None, _) => {}
/// Pair(_, false) => {}
/// }
diff --git a/compiler/rustc_mir_build/src/thir/print.rs b/compiler/rustc_mir_build/src/thir/print.rs
index ed61d6ee7..b2f2a64e2 100644
--- a/compiler/rustc_mir_build/src/thir/print.rs
+++ b/compiler/rustc_mir_build/src/thir/print.rs
@@ -3,7 +3,7 @@ use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::LocalDefId;
use std::fmt::{self, Write};
-pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => {
let thir = thir.steal();
@@ -15,7 +15,7 @@ pub(crate) fn thir_tree(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalD
}
}
-pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: ty::WithOptConstParam<LocalDefId>) -> String {
+pub(crate) fn thir_flat(tcx: TyCtxt<'_>, owner_def: LocalDefId) -> String {
match super::cx::thir_body(tcx, owner_def) {
Ok((thir, _)) => format!("{:#?}", thir.steal()),
Err(_) => "error".into(),
@@ -519,6 +519,19 @@ impl<'a, 'tcx> ThirPrinter<'a, 'tcx> {
self.print_inline_asm_expr(&**expr, depth_lvl + 2);
print_indented!(self, "}", depth_lvl);
}
+ OffsetOf { container, fields } => {
+ print_indented!(self, "OffsetOf {", depth_lvl);
+ print_indented!(self, format!("container: {:?}", container), depth_lvl + 1);
+ print_indented!(self, "fields: [", depth_lvl + 1);
+
+ for field in fields.iter() {
+ print_indented!(self, format!("{:?}", field), depth_lvl + 2);
+ print_indented!(self, ",", depth_lvl + 1);
+ }
+
+ print_indented!(self, "]", depth_lvl + 1);
+ print_indented!(self, "}", depth_lvl);
+ }
ThreadLocalRef(def_id) => {
print_indented!(self, "ThreadLocalRef {", depth_lvl);
print_indented!(self, format!("def_id: {:?}", def_id), depth_lvl + 1);
diff --git a/compiler/rustc_mir_dataflow/Cargo.toml b/compiler/rustc_mir_dataflow/Cargo.toml
index 68c61a18d..4a296bb33 100644
--- a/compiler/rustc_mir_dataflow/Cargo.toml
+++ b/compiler/rustc_mir_dataflow/Cargo.toml
@@ -13,6 +13,7 @@ tracing = "0.1"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_graphviz = { path = "../rustc_graphviz" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
diff --git a/compiler/rustc_mir_dataflow/messages.ftl b/compiler/rustc_mir_dataflow/messages.ftl
index 988541525..5698367e4 100644
--- a/compiler/rustc_mir_dataflow/messages.ftl
+++ b/compiler/rustc_mir_dataflow/messages.ftl
@@ -1,29 +1,29 @@
+mir_dataflow_duplicate_values_for =
+ duplicate values for `{$name}`
+
mir_dataflow_path_must_end_in_filename =
path must end in a filename
-mir_dataflow_unknown_formatter =
- unknown formatter
+mir_dataflow_peek_argument_not_a_local =
+ rustc_peek: argument was not a local
-mir_dataflow_duplicate_values_for =
- duplicate values for `{$name}`
+mir_dataflow_peek_argument_untracked =
+ rustc_peek: argument untracked
-mir_dataflow_requires_an_argument =
- `{$name}` requires an argument
+mir_dataflow_peek_bit_not_set =
+ rustc_peek: bit not set
-mir_dataflow_stop_after_dataflow_ended_compilation =
- stop_after_dataflow ended compilation
+mir_dataflow_peek_must_be_not_temporary =
+ dataflow::sanity_check cannot feed a non-temp to rustc_peek
mir_dataflow_peek_must_be_place_or_ref_place =
rustc_peek: argument expression must be either `place` or `&place`
-mir_dataflow_peek_must_be_not_temporary =
- dataflow::sanity_check cannot feed a non-temp to rustc_peek
-
-mir_dataflow_peek_bit_not_set =
- rustc_peek: bit not set
+mir_dataflow_requires_an_argument =
+ `{$name}` requires an argument
-mir_dataflow_peek_argument_not_a_local =
- rustc_peek: argument was not a local
+mir_dataflow_stop_after_dataflow_ended_compilation =
+ stop_after_dataflow ended compilation
-mir_dataflow_peek_argument_untracked =
- rustc_peek: argument untracked
+mir_dataflow_unknown_formatter =
+ unknown formatter
diff --git a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
index bd8ec82df..d615c83d6 100644
--- a/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_dataflow/src/elaborate_drops.rs
@@ -1,6 +1,6 @@
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::*;
use rustc_middle::traits::Reveal;
@@ -237,6 +237,7 @@ where
place: self.place,
target: self.succ,
unwind: self.unwind.into_action(),
+ replace: false,
},
);
}
@@ -276,6 +277,7 @@ where
assert_eq!(self.elaborator.param_env().reveal(), Reveal::All);
let field_ty =
tcx.normalize_erasing_regions(self.elaborator.param_env(), f.ty(tcx, substs));
+
(tcx.mk_place_field(base_place, field, field_ty), subpath)
})
.collect()
@@ -718,6 +720,7 @@ where
place: tcx.mk_place_deref(ptr),
target: loop_block,
unwind: unwind.into_action(),
+ replace: false,
},
);
@@ -962,8 +965,12 @@ where
}
fn drop_block(&mut self, target: BasicBlock, unwind: Unwind) -> BasicBlock {
- let block =
- TerminatorKind::Drop { place: self.place, target, unwind: unwind.into_action() };
+ let block = TerminatorKind::Drop {
+ place: self.place,
+ target,
+ unwind: unwind.into_action(),
+ replace: false,
+ };
self.new_block(unwind, block)
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/direction.rs b/compiler/rustc_mir_dataflow/src/framework/direction.rs
index c8fe1af66..ba328e780 100644
--- a/compiler/rustc_mir_dataflow/src/framework/direction.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/direction.rs
@@ -479,7 +479,7 @@ impl Direction for Forward {
Goto { target } => propagate(target, exit_state),
Assert { target, unwind, expected: _, msg: _, cond: _ }
- | Drop { target, unwind, place: _ }
+ | Drop { target, unwind, place: _, replace: _ }
| FalseUnwind { real_target: target, unwind } => {
if let UnwindAction::Cleanup(unwind) = unwind {
propagate(unwind, exit_state);
diff --git a/compiler/rustc_mir_dataflow/src/framework/engine.rs b/compiler/rustc_mir_dataflow/src/framework/engine.rs
index 2abdee064..3e8f792e6 100644
--- a/compiler/rustc_mir_dataflow/src/framework/engine.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/engine.rs
@@ -12,7 +12,7 @@ use rustc_ast as ast;
use rustc_data_structures::work_queue::WorkQueue;
use rustc_graphviz as dot;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::{self, traversal, BasicBlock};
use rustc_middle::mir::{create_dump_file, dump_enabled};
use rustc_middle::ty::print::with_no_trimmed_paths;
diff --git a/compiler/rustc_mir_dataflow/src/framework/fmt.rs b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
index 490be166a..6a256fae3 100644
--- a/compiler/rustc_mir_dataflow/src/framework/fmt.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/fmt.rs
@@ -2,7 +2,7 @@
//! analysis.
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use std::fmt;
/// An extension to `fmt::Debug` for data that can be better printed with some auxiliary data `C`.
diff --git a/compiler/rustc_mir_dataflow/src/framework/lattice.rs b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
index 8fdac7b2c..3952f44ad 100644
--- a/compiler/rustc_mir_dataflow/src/framework/lattice.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/lattice.rs
@@ -40,7 +40,7 @@
use crate::framework::BitSetExt;
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use std::iter;
/// A [partially ordered set][poset] that has a [least upper bound][lub] for any pair of elements
@@ -75,12 +75,12 @@ pub trait MeetSemiLattice: Eq {
/// A set that has a "bottom" element, which is less than or equal to any other element.
pub trait HasBottom {
- fn bottom() -> Self;
+ const BOTTOM: Self;
}
/// A set that has a "top" element, which is greater than or equal to any other element.
pub trait HasTop {
- fn top() -> Self;
+ const TOP: Self;
}
/// A `bool` is a "two-point" lattice with `true` as the top element and `false` as the bottom:
@@ -113,15 +113,11 @@ impl MeetSemiLattice for bool {
}
impl HasBottom for bool {
- fn bottom() -> Self {
- false
- }
+ const BOTTOM: Self = false;
}
impl HasTop for bool {
- fn top() -> Self {
- true
- }
+ const TOP: Self = true;
}
/// A tuple (or list) of lattices is itself a lattice whose least upper bound is the concatenation
@@ -274,13 +270,9 @@ impl<T: Clone + Eq> MeetSemiLattice for FlatSet<T> {
}
impl<T> HasBottom for FlatSet<T> {
- fn bottom() -> Self {
- Self::Bottom
- }
+ const BOTTOM: Self = Self::Bottom;
}
impl<T> HasTop for FlatSet<T> {
- fn top() -> Self {
- Self::Top
- }
+ const TOP: Self = Self::Top;
}
diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs
index d9aff94fe..f2263007f 100644
--- a/compiler/rustc_mir_dataflow/src/framework/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs
@@ -33,7 +33,7 @@
use std::cmp::Ordering;
use rustc_index::bit_set::{BitSet, ChunkedBitSet, HybridBitSet};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::{self, BasicBlock, Location};
use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_dataflow/src/framework/tests.rs b/compiler/rustc_mir_dataflow/src/framework/tests.rs
index 60679b17d..0fed305b9 100644
--- a/compiler/rustc_mir_dataflow/src/framework/tests.rs
+++ b/compiler/rustc_mir_dataflow/src/framework/tests.rs
@@ -3,7 +3,7 @@
use std::marker::PhantomData;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::{self, BasicBlock, Location};
use rustc_middle::ty;
use rustc_span::DUMMY_SP;
diff --git a/compiler/rustc_mir_dataflow/src/impls/liveness.rs b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
index 1309ea525..6ae6bdc17 100644
--- a/compiler/rustc_mir_dataflow/src/impls/liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/liveness.rs
@@ -197,6 +197,7 @@ impl DefUse {
| NonMutatingUseContext::Copy
| NonMutatingUseContext::Inspect
| NonMutatingUseContext::Move
+ | NonMutatingUseContext::PlaceMention
| NonMutatingUseContext::ShallowBorrow
| NonMutatingUseContext::SharedBorrow,
) => Some(DefUse::Use),
diff --git a/compiler/rustc_mir_dataflow/src/impls/mod.rs b/compiler/rustc_mir_dataflow/src/impls/mod.rs
index 4b5324e20..171db6965 100644
--- a/compiler/rustc_mir_dataflow/src/impls/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/mod.rs
@@ -3,7 +3,7 @@
//! zero-sized structure.
use rustc_index::bit_set::{BitSet, ChunkedBitSet};
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::visit::{MirVisitable, Visitor};
use rustc_middle::mir::{self, Body, Location};
use rustc_middle::ty::{self, TyCtxt};
@@ -26,7 +26,7 @@ pub use self::borrowed_locals::borrowed_locals;
pub use self::borrowed_locals::MaybeBorrowedLocals;
pub use self::liveness::MaybeLiveLocals;
pub use self::liveness::MaybeTransitiveLiveLocals;
-pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageLive};
+pub use self::storage_liveness::{MaybeRequiresStorage, MaybeStorageDead, MaybeStorageLive};
/// `MaybeInitializedPlaces` tracks all places that might be
/// initialized upon reaching a particular point in the control flow
diff --git a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
index 4a5d9d520..463ce083a 100644
--- a/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
+++ b/compiler/rustc_mir_dataflow/src/impls/storage_liveness.rs
@@ -74,6 +74,73 @@ impl<'tcx, 'a> crate::GenKillAnalysis<'tcx> for MaybeStorageLive<'a> {
}
}
+#[derive(Clone)]
+pub struct MaybeStorageDead {
+ always_live_locals: BitSet<Local>,
+}
+
+impl MaybeStorageDead {
+ pub fn new(always_live_locals: BitSet<Local>) -> Self {
+ MaybeStorageDead { always_live_locals }
+ }
+}
+
+impl<'tcx> crate::AnalysisDomain<'tcx> for MaybeStorageDead {
+ type Domain = BitSet<Local>;
+
+ const NAME: &'static str = "maybe_storage_dead";
+
+ fn bottom_value(&self, body: &mir::Body<'tcx>) -> Self::Domain {
+ // bottom = live
+ BitSet::new_empty(body.local_decls.len())
+ }
+
+ fn initialize_start_block(&self, body: &mir::Body<'tcx>, on_entry: &mut Self::Domain) {
+ assert_eq!(body.local_decls.len(), self.always_live_locals.domain_size());
+ // Do not iterate on return place and args, as they are trivially always live.
+ for local in body.vars_and_temps_iter() {
+ if !self.always_live_locals.contains(local) {
+ on_entry.insert(local);
+ }
+ }
+ }
+}
+
+impl<'tcx> crate::GenKillAnalysis<'tcx> for MaybeStorageDead {
+ type Idx = Local;
+
+ fn statement_effect(
+ &self,
+ trans: &mut impl GenKill<Self::Idx>,
+ stmt: &mir::Statement<'tcx>,
+ _: Location,
+ ) {
+ match stmt.kind {
+ StatementKind::StorageLive(l) => trans.kill(l),
+ StatementKind::StorageDead(l) => trans.gen(l),
+ _ => (),
+ }
+ }
+
+ fn terminator_effect(
+ &self,
+ _trans: &mut impl GenKill<Self::Idx>,
+ _: &mir::Terminator<'tcx>,
+ _: Location,
+ ) {
+ // Terminators have no effect
+ }
+
+ fn call_return_effect(
+ &self,
+ _trans: &mut impl GenKill<Self::Idx>,
+ _block: BasicBlock,
+ _return_places: CallReturnPlaces<'_, 'tcx>,
+ ) {
+ // Nothing to do when a call returns successfully
+ }
+}
+
type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>;
/// Dataflow analysis that determines whether each local requires storage at a
diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs
index 43caa2ea9..fc4efb943 100644
--- a/compiler/rustc_mir_dataflow/src/lib.rs
+++ b/compiler/rustc_mir_dataflow/src/lib.rs
@@ -16,8 +16,8 @@ extern crate rustc_middle;
use rustc_ast::MetaItem;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::def_id::DefId;
-use rustc_macros::fluent_messages;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::symbol::{sym, Symbol};
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
index 64ed7a29f..096bc0acf 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/builder.rs
@@ -1,6 +1,6 @@
use crate::move_paths::FxHashMap;
use crate::un_derefer::UnDerefer;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::tcx::RvalueInitializationState;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
@@ -360,7 +360,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> {
| Rvalue::AddressOf(..)
| Rvalue::Discriminant(..)
| Rvalue::Len(..)
- | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
+ | Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf | NullOp::OffsetOf(..), _) => {}
}
}
diff --git a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
index 257a42cdd..ab1a67153 100644
--- a/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
+++ b/compiler/rustc_mir_dataflow/src/move_paths/mod.rs
@@ -1,6 +1,6 @@
use crate::move_paths::builder::MoveDat;
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::*;
use rustc_middle::ty::{ParamEnv, Ty, TyCtxt};
use rustc_span::Span;
@@ -20,7 +20,7 @@ rustc_index::newtype_index! {
impl polonius_engine::Atom for MovePathIndex {
fn index(self) -> usize {
- rustc_index::vec::Idx::index(self)
+ rustc_index::Idx::index(self)
}
}
diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs
index 98bebc9b1..b74d06e5a 100644
--- a/compiler/rustc_mir_dataflow/src/value_analysis.rs
+++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs
@@ -32,11 +32,14 @@
//! Because of that, we can assume that the only way to change the value behind a tracked place is
//! by direct assignment.
+use std::collections::VecDeque;
use std::fmt::{Debug, Formatter};
+use std::ops::Range;
use rustc_data_structures::fx::FxHashMap;
+use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -65,8 +68,8 @@ pub trait ValueAnalysis<'tcx> {
StatementKind::Assign(box (place, rvalue)) => {
self.handle_assign(*place, rvalue, state);
}
- StatementKind::SetDiscriminant { box ref place, .. } => {
- state.flood_discr(place.as_ref(), self.map());
+ StatementKind::SetDiscriminant { box place, variant_index } => {
+ self.handle_set_discriminant(*place, *variant_index, state);
}
StatementKind::Intrinsic(box intrinsic) => {
self.handle_intrinsic(intrinsic, state);
@@ -74,11 +77,11 @@ pub trait ValueAnalysis<'tcx> {
StatementKind::StorageLive(local) | StatementKind::StorageDead(local) => {
// StorageLive leaves the local in an uninitialized state.
// StorageDead makes it UB to access the local afterwards.
- state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::bottom());
+ state.flood_with(Place::from(*local).as_ref(), self.map(), Self::Value::BOTTOM);
}
StatementKind::Deinit(box place) => {
// Deinit makes the place uninitialized.
- state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
+ state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
}
StatementKind::Retag(..) => {
// We don't track references.
@@ -92,6 +95,24 @@ pub trait ValueAnalysis<'tcx> {
}
}
+ fn handle_set_discriminant(
+ &self,
+ place: Place<'tcx>,
+ variant_index: VariantIdx,
+ state: &mut State<Self::Value>,
+ ) {
+ self.super_set_discriminant(place, variant_index, state)
+ }
+
+ fn super_set_discriminant(
+ &self,
+ place: Place<'tcx>,
+ _variant_index: VariantIdx,
+ state: &mut State<Self::Value>,
+ ) {
+ state.flood_discr(place.as_ref(), self.map());
+ }
+
fn handle_intrinsic(
&self,
intrinsic: &NonDivergingIntrinsic<'tcx>,
@@ -103,16 +124,18 @@ pub trait ValueAnalysis<'tcx> {
fn super_intrinsic(
&self,
intrinsic: &NonDivergingIntrinsic<'tcx>,
- state: &mut State<Self::Value>,
+ _state: &mut State<Self::Value>,
) {
match intrinsic {
NonDivergingIntrinsic::Assume(..) => {
// Could use this, but ignoring it is sound.
}
- NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping { dst, .. }) => {
- if let Some(place) = dst.place() {
- state.flood(place.as_ref(), self.map());
- }
+ NonDivergingIntrinsic::CopyNonOverlapping(CopyNonOverlapping {
+ dst: _,
+ src: _,
+ count: _,
+ }) => {
+ // This statement represents `*dst = *src`, `count` times.
}
}
}
@@ -154,7 +177,7 @@ pub trait ValueAnalysis<'tcx> {
Rvalue::CopyForDeref(place) => self.handle_operand(&Operand::Copy(*place), state),
Rvalue::Ref(..) | Rvalue::AddressOf(..) => {
// We don't track such places.
- ValueOrPlace::top()
+ ValueOrPlace::TOP
}
Rvalue::Repeat(..)
| Rvalue::ThreadLocalRef(..)
@@ -168,7 +191,7 @@ pub trait ValueAnalysis<'tcx> {
| Rvalue::Aggregate(..)
| Rvalue::ShallowInitBox(..) => {
// No modification is possible through these r-values.
- ValueOrPlace::top()
+ ValueOrPlace::TOP
}
}
}
@@ -196,7 +219,7 @@ pub trait ValueAnalysis<'tcx> {
self.map()
.find(place.as_ref())
.map(ValueOrPlace::Place)
- .unwrap_or(ValueOrPlace::top())
+ .unwrap_or(ValueOrPlace::TOP)
}
}
}
@@ -214,7 +237,7 @@ pub trait ValueAnalysis<'tcx> {
_constant: &Constant<'tcx>,
_state: &mut State<Self::Value>,
) -> Self::Value {
- Self::Value::top()
+ Self::Value::TOP
}
/// The effect of a successful function call return should not be
@@ -229,7 +252,7 @@ pub trait ValueAnalysis<'tcx> {
// Effect is applied by `handle_call_return`.
}
TerminatorKind::Drop { place, .. } => {
- state.flood_with(place.as_ref(), self.map(), Self::Value::bottom());
+ state.flood_with(place.as_ref(), self.map(), Self::Value::BOTTOM);
}
TerminatorKind::Yield { .. } => {
// They would have an effect, but are not allowed in this phase.
@@ -307,7 +330,7 @@ impl<'tcx, T: ValueAnalysis<'tcx>> AnalysisDomain<'tcx> for ValueAnalysisWrapper
fn initialize_start_block(&self, body: &Body<'tcx>, state: &mut Self::Domain) {
// The initial state maps all tracked places of argument projections to ⊤ and the rest to ⊥.
assert!(matches!(state.0, StateData::Unreachable));
- let values = IndexVec::from_elem_n(T::Value::bottom(), self.0.map().value_count);
+ let values = IndexVec::from_elem_n(T::Value::BOTTOM, self.0.map().value_count);
*state = State(StateData::Reachable(values));
for arg in body.args_iter() {
state.flood(PlaceRef { local: arg, projection: &[] }, self.0.map());
@@ -366,7 +389,7 @@ where
rustc_index::newtype_index!(
/// This index uniquely identifies a place.
///
- /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` correspondends to a tracked
+ /// Not every place has a `PlaceIndex`, and not every `PlaceIndex` corresponds to a tracked
/// place. However, every tracked place and all places along its projection have a `PlaceIndex`.
pub struct PlaceIndex {}
);
@@ -437,7 +460,7 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
}
pub fn flood_all(&mut self) {
- self.flood_all_with(V::top())
+ self.flood_all_with(V::TOP)
}
pub fn flood_all_with(&mut self, value: V) {
@@ -447,28 +470,24 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
pub fn flood_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
let StateData::Reachable(values) = &mut self.0 else { return };
- map.for_each_aliasing_place(place, None, &mut |place| {
- if let Some(vi) = map.places[place].value_index {
- values[vi] = value.clone();
- }
+ map.for_each_aliasing_place(place, None, &mut |vi| {
+ values[vi] = value.clone();
});
}
pub fn flood(&mut self, place: PlaceRef<'_>, map: &Map) {
- self.flood_with(place, map, V::top())
+ self.flood_with(place, map, V::TOP)
}
pub fn flood_discr_with(&mut self, place: PlaceRef<'_>, map: &Map, value: V) {
let StateData::Reachable(values) = &mut self.0 else { return };
- map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |place| {
- if let Some(vi) = map.places[place].value_index {
- values[vi] = value.clone();
- }
+ map.for_each_aliasing_place(place, Some(TrackElem::Discriminant), &mut |vi| {
+ values[vi] = value.clone();
});
}
pub fn flood_discr(&mut self, place: PlaceRef<'_>, map: &Map) {
- self.flood_discr_with(place, map, V::top())
+ self.flood_discr_with(place, map, V::TOP)
}
/// Low-level method that assigns to a place.
@@ -538,14 +557,14 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
pub fn get(&self, place: PlaceRef<'_>, map: &Map) -> V {
- map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::top())
+ map.find(place).map(|place| self.get_idx(place, map)).unwrap_or(V::TOP)
}
/// Retrieve the value stored for a place, or ⊤ if it is not tracked.
pub fn get_discr(&self, place: PlaceRef<'_>, map: &Map) -> V {
match map.find_discr(place) {
Some(place) => self.get_idx(place, map),
- None => V::top(),
+ None => V::TOP,
}
}
@@ -553,11 +572,11 @@ impl<V: Clone + HasTop + HasBottom> State<V> {
pub fn get_idx(&self, place: PlaceIndex, map: &Map) -> V {
match &self.0 {
StateData::Reachable(values) => {
- map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::top())
+ map.places[place].value_index.map(|v| values[v].clone()).unwrap_or(V::TOP)
}
StateData::Unreachable => {
// Because this is unreachable, we can return any value we want.
- V::bottom()
+ V::BOTTOM
}
}
}
@@ -588,6 +607,9 @@ pub struct Map {
projections: FxHashMap<(PlaceIndex, TrackElem), PlaceIndex>,
places: IndexVec<PlaceIndex, PlaceInfo>,
value_count: usize,
+ // The Range corresponds to a slice into `inner_values_buffer`.
+ inner_values: IndexVec<PlaceIndex, Range<usize>>,
+ inner_values_buffer: Vec<ValueIndex>,
}
impl Map {
@@ -597,6 +619,8 @@ impl Map {
projections: FxHashMap::default(),
places: IndexVec::new(),
value_count: 0,
+ inner_values: IndexVec::new(),
+ inner_values_buffer: Vec::new(),
}
}
@@ -608,12 +632,12 @@ impl Map {
pub fn from_filter<'tcx>(
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
- filter: impl FnMut(Ty<'tcx>) -> bool,
- place_limit: Option<usize>,
+ filter: impl Fn(Ty<'tcx>) -> bool,
+ value_limit: Option<usize>,
) -> Self {
let mut map = Self::new();
let exclude = excluded_locals(body);
- map.register_with_filter(tcx, body, filter, exclude, place_limit);
+ map.register_with_filter(tcx, body, filter, exclude, value_limit);
debug!("registered {} places ({} nodes in total)", map.value_count, map.places.len());
map
}
@@ -623,51 +647,90 @@ impl Map {
&mut self,
tcx: TyCtxt<'tcx>,
body: &Body<'tcx>,
- mut filter: impl FnMut(Ty<'tcx>) -> bool,
+ filter: impl Fn(Ty<'tcx>) -> bool,
exclude: BitSet<Local>,
- place_limit: Option<usize>,
+ value_limit: Option<usize>,
) {
- // We use this vector as stack, pushing and popping projections.
- let mut projection = Vec::new();
+ let mut worklist = VecDeque::with_capacity(value_limit.unwrap_or(body.local_decls.len()));
+
+ // Start by constructing the places for each bare local.
+ self.locals = IndexVec::from_elem(None, &body.local_decls);
for (local, decl) in body.local_decls.iter_enumerated() {
- if !exclude.contains(local) {
- self.register_with_filter_rec(
- tcx,
- local,
- &mut projection,
- decl.ty,
- &mut filter,
- place_limit,
- );
+ if exclude.contains(local) {
+ continue;
}
+
+ // Create a place for the local.
+ debug_assert!(self.locals[local].is_none());
+ let place = self.places.push(PlaceInfo::new(None));
+ self.locals[local] = Some(place);
+
+ // And push the eventual children places to the worklist.
+ self.register_children(tcx, place, decl.ty, &filter, &mut worklist);
}
+
+ // `place.elem1.elem2` with type `ty`.
+ // `elem1` is either `Some(Variant(i))` or `None`.
+ while let Some((mut place, elem1, elem2, ty)) = worklist.pop_front() {
+ // The user requires a bound on the number of created values.
+ if let Some(value_limit) = value_limit && self.value_count >= value_limit {
+ break
+ }
+
+ // Create a place for this projection.
+ for elem in [elem1, Some(elem2)].into_iter().flatten() {
+ place = *self.projections.entry((place, elem)).or_insert_with(|| {
+ // Prepend new child to the linked list.
+ let next = self.places.push(PlaceInfo::new(Some(elem)));
+ self.places[next].next_sibling = self.places[place].first_child;
+ self.places[place].first_child = Some(next);
+ next
+ });
+ }
+
+ // And push the eventual children places to the worklist.
+ self.register_children(tcx, place, ty, &filter, &mut worklist);
+ }
+
+ // Pre-compute the tree of ValueIndex nested in each PlaceIndex.
+ // `inner_values_buffer[inner_values[place]]` is the set of all the values
+ // reachable by projecting `place`.
+ self.inner_values_buffer = Vec::with_capacity(self.value_count);
+ self.inner_values = IndexVec::from_elem(0..0, &self.places);
+ for local in body.local_decls.indices() {
+ if let Some(place) = self.locals[local] {
+ self.cache_preorder_invoke(place);
+ }
+ }
+
+ // Trim useless places.
+ for opt_place in self.locals.iter_mut() {
+ if let Some(place) = *opt_place && self.inner_values[place].is_empty() {
+ *opt_place = None;
+ }
+ }
+ #[allow(rustc::potential_query_instability)]
+ self.projections.retain(|_, child| !self.inner_values[*child].is_empty());
}
/// Potentially register the (local, projection) place and its fields, recursively.
///
/// Invariant: The projection must only contain trackable elements.
- fn register_with_filter_rec<'tcx>(
+ fn register_children<'tcx>(
&mut self,
tcx: TyCtxt<'tcx>,
- local: Local,
- projection: &mut Vec<PlaceElem<'tcx>>,
+ place: PlaceIndex,
ty: Ty<'tcx>,
- filter: &mut impl FnMut(Ty<'tcx>) -> bool,
- place_limit: Option<usize>,
+ filter: &impl Fn(Ty<'tcx>) -> bool,
+ worklist: &mut VecDeque<(PlaceIndex, Option<TrackElem>, TrackElem, Ty<'tcx>)>,
) {
- if let Some(place_limit) = place_limit && self.value_count >= place_limit {
- return
- }
-
- // We know that the projection only contains trackable elements.
- let place = self.make_place(local, projection).unwrap();
-
// Allocate a value slot if it doesn't have one, and the user requested one.
if self.places[place].value_index.is_none() && filter(ty) {
self.places[place].value_index = Some(self.value_count.into());
self.value_count += 1;
}
+ // For enums, directly create the `Discriminant`, as that's their main use.
if ty.is_enum() {
let discr_ty = ty.discriminant_ty(tcx);
if filter(discr_ty) {
@@ -692,46 +755,32 @@ impl Map {
// Recurse with all fields of this place.
iter_fields(ty, tcx, ty::ParamEnv::reveal_all(), |variant, field, ty| {
- if let Some(variant) = variant {
- projection.push(PlaceElem::Downcast(None, variant));
- let _ = self.make_place(local, projection);
- projection.push(PlaceElem::Field(field, ty));
- self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit);
- projection.pop();
- projection.pop();
- return;
- }
- projection.push(PlaceElem::Field(field, ty));
- self.register_with_filter_rec(tcx, local, projection, ty, filter, place_limit);
- projection.pop();
+ worklist.push_back((
+ place,
+ variant.map(TrackElem::Variant),
+ TrackElem::Field(field),
+ ty,
+ ))
});
}
- /// Tries to add the place to the map, without allocating a value slot.
- ///
- /// Can fail if the projection contains non-trackable elements.
- fn make_place<'tcx>(
- &mut self,
- local: Local,
- projection: &[PlaceElem<'tcx>],
- ) -> Result<PlaceIndex, ()> {
- // Get the base index of the local.
- let mut index =
- *self.locals.get_or_insert_with(local, || self.places.push(PlaceInfo::new(None)));
-
- // Apply the projection.
- for &elem in projection {
- let elem = elem.try_into()?;
- index = *self.projections.entry((index, elem)).or_insert_with(|| {
- // Prepend new child to the linked list.
- let next = self.places.push(PlaceInfo::new(Some(elem)));
- self.places[next].next_sibling = self.places[index].first_child;
- self.places[index].first_child = Some(next);
- next
- });
+ /// Precompute the list of values inside `root` and store it inside
+ /// as a slice within `inner_values_buffer`.
+ fn cache_preorder_invoke(&mut self, root: PlaceIndex) {
+ let start = self.inner_values_buffer.len();
+ if let Some(vi) = self.places[root].value_index {
+ self.inner_values_buffer.push(vi);
+ }
+
+ // We manually iterate instead of using `children` as we need to mutate `self`.
+ let mut next_child = self.places[root].first_child;
+ while let Some(child) = next_child {
+ ensure_sufficient_stack(|| self.cache_preorder_invoke(child));
+ next_child = self.places[child].next_sibling;
}
- Ok(index)
+ let end = self.inner_values_buffer.len();
+ self.inner_values[root] = start..end;
}
/// Returns the number of tracked places, i.e., those for which a value can be stored.
@@ -750,7 +799,7 @@ impl Map {
place: PlaceRef<'_>,
extra: impl IntoIterator<Item = TrackElem>,
) -> Option<PlaceIndex> {
- let mut index = *self.locals.get(place.local)?.as_ref()?;
+ let mut index = *self.locals[place.local].as_ref()?;
for &elem in place.projection {
index = self.apply(index, elem.try_into().ok()?)?;
@@ -784,17 +833,17 @@ impl Map {
///
/// `tail_elem` allows to support discriminants that are not a place in MIR, but that we track
/// as such.
- pub fn for_each_aliasing_place(
+ fn for_each_aliasing_place(
&self,
place: PlaceRef<'_>,
tail_elem: Option<TrackElem>,
- f: &mut impl FnMut(PlaceIndex),
+ f: &mut impl FnMut(ValueIndex),
) {
- if place.is_indirect() {
+ if place.has_deref() {
// We do not track indirect places.
return;
}
- let Some(&Some(mut index)) = self.locals.get(place.local) else {
+ let Some(mut index) = self.locals[place.local] else {
// The local is not tracked at all, so it does not alias anything.
return;
};
@@ -805,7 +854,9 @@ impl Map {
.chain(tail_elem.map(Ok).into_iter());
for elem in elems {
// A field aliases the parent place.
- f(index);
+ if let Some(vi) = self.places[index].value_index {
+ f(vi);
+ }
let Ok(elem) = elem else { return };
let sub = self.apply(index, elem);
@@ -819,7 +870,7 @@ impl Map {
return;
}
}
- self.preorder_invoke(index, f);
+ self.for_each_value_inside(index, f);
}
/// Invoke the given function on all the descendants of the given place, except one branch.
@@ -827,7 +878,7 @@ impl Map {
&self,
parent: PlaceIndex,
preserved_child: Option<PlaceIndex>,
- f: &mut impl FnMut(PlaceIndex),
+ f: &mut impl FnMut(ValueIndex),
) {
for sibling in self.children(parent) {
let elem = self.places[sibling].proj_elem;
@@ -837,16 +888,17 @@ impl Map {
// Only invalidate the other variants, the current one is fine.
&& Some(sibling) != preserved_child
{
- self.preorder_invoke(sibling, f);
+ self.for_each_value_inside(sibling, f);
}
}
}
- /// Invoke a function on the given place and all descendants.
- fn preorder_invoke(&self, root: PlaceIndex, f: &mut impl FnMut(PlaceIndex)) {
- f(root);
- for child in self.children(root) {
- self.preorder_invoke(child, f);
+ /// Invoke a function on each value in the given place and all descendants.
+ fn for_each_value_inside(&self, root: PlaceIndex, f: &mut impl FnMut(ValueIndex)) {
+ let range = self.inner_values[root].clone();
+ let values = &self.inner_values_buffer[range];
+ for &v in values {
+ f(v)
}
}
}
@@ -909,9 +961,7 @@ pub enum ValueOrPlace<V> {
}
impl<V: HasTop> ValueOrPlace<V> {
- pub fn top() -> Self {
- ValueOrPlace::Value(V::top())
- }
+ pub const TOP: Self = ValueOrPlace::Value(V::TOP);
}
/// The set of projection elements that can be used by a tracked place.
diff --git a/compiler/rustc_mir_transform/Cargo.toml b/compiler/rustc_mir_transform/Cargo.toml
index 962536669..eca5f98a2 100644
--- a/compiler/rustc_mir_transform/Cargo.toml
+++ b/compiler/rustc_mir_transform/Cargo.toml
@@ -24,6 +24,8 @@ rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
rustc_trait_selection = { path = "../rustc_trait_selection" }
rustc_span = { path = "../rustc_span" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
+rustc_macros = { path = "../rustc_macros" }
[dev-dependencies]
coverage_test_macros = { path = "src/coverage/test_macros" }
diff --git a/compiler/rustc_mir_transform/messages.ftl b/compiler/rustc_mir_transform/messages.ftl
new file mode 100644
index 000000000..b13429d12
--- /dev/null
+++ b/compiler/rustc_mir_transform/messages.ftl
@@ -0,0 +1,67 @@
+mir_transform_arithmetic_overflow = this arithmetic operation will overflow
+mir_transform_call_to_unsafe_label = call to unsafe function
+mir_transform_call_to_unsafe_note = consult the function's documentation for information on how to avoid undefined behavior
+mir_transform_const_defined_here = `const` item defined here
+
+mir_transform_const_modify = attempting to modify a `const` item
+ .note = each usage of a `const` item creates a new temporary; the original `const` item will not be modified
+
+mir_transform_const_mut_borrow = taking a mutable reference to a `const` item
+ .note = each usage of a `const` item creates a new temporary
+ .note2 = the mutable reference will refer to this temporary, not the original `const` item
+ .note3 = mutable reference created due to call to this method
+
+mir_transform_const_ptr2int_label = cast of pointer to int
+mir_transform_const_ptr2int_note = casting pointers to integers in constants
+mir_transform_deref_ptr_label = dereference of raw pointer
+mir_transform_deref_ptr_note = raw pointers may be null, dangling or unaligned; they can violate aliasing rules and cause data races: all of these are undefined behavior
+mir_transform_ffi_unwind_call = call to {$foreign ->
+ [true] foreign function
+ *[false] function pointer
+ } with FFI-unwind ABI
+
+mir_transform_fn_item_ref = taking a reference to a function item does not give a function pointer
+ .suggestion = cast `{$ident}` to obtain a function pointer
+
+mir_transform_initializing_valid_range_label = initializing type with `rustc_layout_scalar_valid_range` attr
+mir_transform_initializing_valid_range_note = initializing a layout restricted type's field with a value outside the valid range is undefined behavior
+mir_transform_must_not_suspend = {$pre}`{$def_path}`{$post} held across a suspend point, but should not be
+ .label = the value is held across this suspend point
+ .note = {$reason}
+ .help = consider using a block (`{"{ ... }"}`) to shrink the value's scope, ending before the suspend point
+
+mir_transform_mutation_layout_constrained_borrow_label = borrow of layout constrained field with interior mutability
+mir_transform_mutation_layout_constrained_borrow_note = references to fields of layout constrained fields lose the constraints. Coupled with interior mutability, the field can be changed to invalid values
+mir_transform_mutation_layout_constrained_label = mutation of layout constrained field
+mir_transform_mutation_layout_constrained_note = mutating layout constrained fields cannot statically be checked for valid values
+mir_transform_operation_will_panic = this operation will panic at runtime
+
+mir_transform_requires_unsafe = {$details} is unsafe and requires unsafe {$op_in_unsafe_fn_allowed ->
+ [true] function or block
+ *[false] block
+ }
+ .not_inherited = items do not inherit unsafety from separate enclosing items
+
+mir_transform_simd_shuffle_last_const = last argument of `simd_shuffle` is required to be a `const` item
+
+mir_transform_target_feature_call_label = call to function with `#[target_feature]`
+mir_transform_target_feature_call_note = can only be called if the required target features are available
+
+mir_transform_unaligned_packed_ref = reference to packed field is unaligned
+ .note = packed structs are only aligned by one byte, and many modern architectures penalize unaligned field accesses
+ .note_ub = creating a misaligned reference is undefined behavior (even if that reference is never dereferenced)
+ .help = copy the field contents to a local variable, or replace the reference with a raw pointer and use `read_unaligned`/`write_unaligned` (loads and stores via `*p` must be properly aligned even when using raw pointers)
+
+mir_transform_union_access_label = access to union field
+mir_transform_union_access_note = the field may not be properly initialized: using uninitialized data will cause undefined behavior
+mir_transform_unsafe_op_in_unsafe_fn = {$details} is unsafe and requires unsafe block (error E0133)
+
+mir_transform_unused_unsafe = unnecessary `unsafe` block
+ .label = because it's nested under this `unsafe` block
+
+mir_transform_use_of_asm_label = use of inline assembly
+mir_transform_use_of_asm_note = inline assembly is entirely unchecked and can cause undefined behavior
+mir_transform_use_of_extern_static_label = use of extern static
+mir_transform_use_of_extern_static_note = extern statics are not controlled by the Rust type system: invalid data, aliasing violations or data races will cause undefined behavior
+mir_transform_use_of_static_mut_label = use of mutable static
+mir_transform_use_of_static_mut_note = mutable statics can be mutated by multiple threads: aliasing violations or data races will cause undefined behavior
diff --git a/compiler/rustc_mir_transform/src/add_call_guards.rs b/compiler/rustc_mir_transform/src/add_call_guards.rs
index e1e354efa..fb4705e07 100644
--- a/compiler/rustc_mir_transform/src/add_call_guards.rs
+++ b/compiler/rustc_mir_transform/src/add_call_guards.rs
@@ -1,5 +1,5 @@
use crate::MirPass;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
diff --git a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
index 896fcd9cd..ef2a0c790 100644
--- a/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
+++ b/compiler/rustc_mir_transform/src/add_moves_for_packed_drops.rs
@@ -10,7 +10,7 @@ use rustc_middle::mir::patch::MirPatch;
/// they are dropped from an aligned address.
///
/// For example, if we have something like
-/// ```ignore (ilustrative)
+/// ```ignore (illustrative)
/// #[repr(packed)]
/// struct Foo {
/// dealign: u8,
@@ -25,7 +25,7 @@ use rustc_middle::mir::patch::MirPatch;
/// its address is not aligned.
///
/// Instead, we move `foo.data` to a local and drop that:
-/// ```ignore (ilustrative)
+/// ```ignore (illustrative)
/// storage.live(drop_temp)
/// drop_temp = foo.data;
/// drop(drop_temp) -> next
@@ -80,7 +80,7 @@ fn add_move_for_packed_drop<'tcx>(
is_cleanup: bool,
) {
debug!("add_move_for_packed_drop({:?} @ {:?})", terminator, loc);
- let TerminatorKind::Drop { ref place, target, unwind } = terminator.kind else {
+ let TerminatorKind::Drop { ref place, target, unwind, replace } = terminator.kind else {
unreachable!();
};
@@ -98,6 +98,11 @@ fn add_move_for_packed_drop<'tcx>(
patch.add_assign(loc, Place::from(temp), Rvalue::Use(Operand::Move(*place)));
patch.patch_terminator(
loc.block,
- TerminatorKind::Drop { place: Place::from(temp), target: storage_dead_block, unwind },
+ TerminatorKind::Drop {
+ place: Place::from(temp),
+ target: storage_dead_block,
+ unwind,
+ replace,
+ },
);
}
diff --git a/compiler/rustc_mir_transform/src/add_retag.rs b/compiler/rustc_mir_transform/src/add_retag.rs
index 916f2904d..187d38b38 100644
--- a/compiler/rustc_mir_transform/src/add_retag.rs
+++ b/compiler/rustc_mir_transform/src/add_retag.rs
@@ -59,7 +59,7 @@ impl<'tcx> MirPass<'tcx> for AddRetag {
let basic_blocks = body.basic_blocks.as_mut();
let local_decls = &body.local_decls;
let needs_retag = |place: &Place<'tcx>| {
- !place.has_deref() // we're not eally interested in stores to "outside" locations, they are hard to keep track of anyway
+ !place.has_deref() // we're not really interested in stores to "outside" locations, they are hard to keep track of anyway
&& may_contain_reference(place.ty(&*local_decls, tcx).ty, /*depth*/ 3, tcx)
&& !local_decls[place.local].is_deref_temp()
};
diff --git a/compiler/rustc_mir_transform/src/check_alignment.rs b/compiler/rustc_mir_transform/src/check_alignment.rs
index 9311666c9..ea0780688 100644
--- a/compiler/rustc_mir_transform/src/check_alignment.rs
+++ b/compiler/rustc_mir_transform/src/check_alignment.rs
@@ -1,7 +1,7 @@
use crate::MirPass;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::*;
use rustc_middle::mir::{
interpret::{ConstValue, Scalar},
@@ -14,6 +14,10 @@ pub struct CheckAlignment;
impl<'tcx> MirPass<'tcx> for CheckAlignment {
fn is_enabled(&self, sess: &Session) -> bool {
+ // FIXME(#112480) MSVC and rustc disagree on minimum stack alignment on x86 Windows
+ if sess.target.llvm_target == "i686-pc-windows-msvc" {
+ return false;
+ }
sess.opts.debug_assertions
}
@@ -232,10 +236,10 @@ fn insert_alignment_check<'tcx>(
cond: Operand::Copy(is_ok),
expected: true,
target: new_block,
- msg: AssertKind::MisalignedPointerDereference {
+ msg: Box::new(AssertKind::MisalignedPointerDereference {
required: Operand::Copy(alignment),
found: Operand::Copy(addr),
- },
+ }),
unwind: UnwindAction::Terminate,
},
});
diff --git a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
index 3d32c5865..b79150737 100644
--- a/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
+++ b/compiler/rustc_mir_transform/src/check_const_item_mutation.rs
@@ -1,11 +1,12 @@
-use rustc_errors::{DiagnosticBuilder, DiagnosticMessage};
+use rustc_hir::HirId;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::CONST_ITEM_MUTATION;
use rustc_span::def_id::DefId;
+use rustc_span::Span;
-use crate::MirLint;
+use crate::{errors, MirLint};
pub struct CheckConstItemMutation;
@@ -58,16 +59,14 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
}
}
- fn lint_const_item_usage(
+ /// If we should lint on this usage, return the [`HirId`], source [`Span`]
+ /// and [`Span`] of the const item to use in the lint.
+ fn should_lint_const_item_usage(
&self,
place: &Place<'tcx>,
const_item: DefId,
location: Location,
- msg: impl Into<DiagnosticMessage>,
- decorate: impl for<'a, 'b> FnOnce(
- &'a mut DiagnosticBuilder<'b, ()>,
- ) -> &'a mut DiagnosticBuilder<'b, ()>,
- ) {
+ ) -> Option<(HirId, Span, Span)> {
// Don't lint on borrowing/assigning when a dereference is involved.
// If we 'leave' the temporary via a dereference, we must
// be modifying something else
@@ -83,16 +82,9 @@ impl<'tcx> ConstMutationChecker<'_, 'tcx> {
.assert_crate_local()
.lint_root;
- self.tcx.struct_span_lint_hir(
- CONST_ITEM_MUTATION,
- lint_root,
- source_info.span,
- msg,
- |lint| {
- decorate(lint)
- .span_note(self.tcx.def_span(const_item), "`const` item defined here")
- },
- );
+ Some((lint_root, source_info.span, self.tcx.def_span(const_item)))
+ } else {
+ None
}
}
}
@@ -104,10 +96,14 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// Assigning directly to a constant (e.g. `FOO = true;`) is a hard error,
// so emitting a lint would be redundant.
if !lhs.projection.is_empty() {
- if let Some(def_id) = self.is_const_item_without_destructor(lhs.local) {
- self.lint_const_item_usage(&lhs, def_id, loc, "attempting to modify a `const` item",|lint| {
- lint.note("each usage of a `const` item creates a new temporary; the original `const` item will not be modified")
- })
+ if let Some(def_id) = self.is_const_item_without_destructor(lhs.local)
+ && let Some((lint_root, span, item)) = self.should_lint_const_item_usage(&lhs, def_id, loc) {
+ self.tcx.emit_spanned_lint(
+ CONST_ITEM_MUTATION,
+ lint_root,
+ span,
+ errors::ConstMutate::Modify { konst: item }
+ );
}
}
// We are looking for MIR of the form:
@@ -134,21 +130,31 @@ impl<'tcx> Visitor<'tcx> for ConstMutationChecker<'_, 'tcx> {
// the `self` parameter of a method call (as the terminator of our current
// BasicBlock). If so, we emit a more specific lint.
let method_did = self.target_local.and_then(|target_local| {
- crate::util::find_self_call(self.tcx, &self.body, target_local, loc.block)
+ rustc_middle::util::find_self_call(
+ self.tcx,
+ &self.body,
+ target_local,
+ loc.block,
+ )
});
let lint_loc =
if method_did.is_some() { self.body.terminator_loc(loc.block) } else { loc };
- self.lint_const_item_usage(place, def_id, lint_loc, "taking a mutable reference to a `const` item", |lint| {
- lint
- .note("each usage of a `const` item creates a new temporary")
- .note("the mutable reference will refer to this temporary, not the original `const` item");
-
- if let Some((method_did, _substs)) = method_did {
- lint.span_note(self.tcx.def_span(method_did), "mutable reference created due to call to this method");
- }
- lint
- });
+ let method_call = if let Some((method_did, _)) = method_did {
+ Some(self.tcx.def_span(method_did))
+ } else {
+ None
+ };
+ if let Some((lint_root, span, item)) =
+ self.should_lint_const_item_usage(place, def_id, lint_loc)
+ {
+ self.tcx.emit_spanned_lint(
+ CONST_ITEM_MUTATION,
+ lint_root,
+ span,
+ errors::ConstMutate::MutBorrow { method_call, konst: item },
+ );
+ }
}
}
self.super_rvalue(rvalue, loc);
diff --git a/compiler/rustc_mir_transform/src/check_packed_ref.rs b/compiler/rustc_mir_transform/src/check_packed_ref.rs
index f5f1c1010..2e6cf603d 100644
--- a/compiler/rustc_mir_transform/src/check_packed_ref.rs
+++ b/compiler/rustc_mir_transform/src/check_packed_ref.rs
@@ -1,10 +1,9 @@
-use rustc_errors::struct_span_err;
use rustc_middle::mir::visit::{PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
-use crate::util;
use crate::MirLint;
+use crate::{errors, util};
pub struct CheckPackedRef;
@@ -49,22 +48,7 @@ impl<'tcx> Visitor<'tcx> for PackedRefChecker<'_, 'tcx> {
// shouldn't do.
span_bug!(self.source_info.span, "builtin derive created an unaligned reference");
} else {
- struct_span_err!(
- self.tcx.sess,
- self.source_info.span,
- E0793,
- "reference to packed field is unaligned"
- )
- .note(
- "fields of packed structs are not properly aligned, and creating \
- a misaligned reference is undefined behavior (even if that \
- reference is never dereferenced)",
- ).help(
- "copy the field contents to a local variable, or replace the \
- reference with a raw pointer and use `read_unaligned`/`write_unaligned` \
- (loads and stores via `*p` must be properly aligned even when using raw pointers)"
- )
- .emit();
+ self.tcx.sess.emit_err(errors::UnalignedPackedRef { span: self.source_info.span });
}
}
}
diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs
index d908f6b3a..069514d8a 100644
--- a/compiler/rustc_mir_transform/src/check_unsafety.rs
+++ b/compiler/rustc_mir_transform/src/check_unsafety.rs
@@ -1,5 +1,4 @@
use rustc_data_structures::unord::{UnordItems, UnordSet};
-use rustc_errors::struct_span_err;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId};
@@ -8,13 +7,15 @@ use rustc_hir::intravisit;
use rustc_hir::{BlockCheckMode, ExprKind, Node};
use rustc_middle::mir::visit::{MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{UNSAFE_OP_IN_UNSAFE_FN, UNUSED_UNSAFE};
use rustc_session::lint::Level;
use std::ops::Bound;
+use crate::errors;
+
pub struct UnsafetyChecker<'a, 'tcx> {
body: &'a Body<'tcx>,
body_did: LocalDefId,
@@ -148,7 +149,7 @@ impl<'tcx> Visitor<'tcx> for UnsafetyChecker<'_, 'tcx> {
if let Some(uv) = maybe_uneval {
if uv.promoted.is_none() {
- let def_id = uv.def.def_id_for_type_of();
+ let def_id = uv.def;
if self.tcx.def_kind(def_id) == DefKind::InlineConst {
let local_def_id = def_id.expect_local();
let UnsafetyCheckResult { violations, used_unsafe_blocks, .. } =
@@ -375,22 +376,7 @@ impl<'tcx> UnsafetyChecker<'_, 'tcx> {
}
pub(crate) fn provide(providers: &mut Providers) {
- *providers = Providers {
- unsafety_check_result: |tcx, def_id| {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.unsafety_check_result_for_const_arg(def)
- } else {
- unsafety_check_result(tcx, ty::WithOptConstParam::unknown(def_id))
- }
- },
- unsafety_check_result_for_const_arg: |tcx, (did, param_did)| {
- unsafety_check_result(
- tcx,
- ty::WithOptConstParam { did, const_param_did: Some(param_did) },
- )
- },
- ..*providers
- };
+ *providers = Providers { unsafety_check_result, ..*providers };
}
/// Context information for [`UnusedUnsafeVisitor`] traversal,
@@ -492,10 +478,7 @@ fn check_unused_unsafe(
unused_unsafes
}
-fn unsafety_check_result(
- tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> &UnsafetyCheckResult {
+fn unsafety_check_result(tcx: TyCtxt<'_>, def: LocalDefId) -> &UnsafetyCheckResult {
debug!("unsafety_violations({:?})", def);
// N.B., this borrow is valid because all the consumers of
@@ -510,13 +493,13 @@ fn unsafety_check_result(
});
}
- let param_env = tcx.param_env(def.did);
+ let param_env = tcx.param_env(def);
- let mut checker = UnsafetyChecker::new(body, def.did, tcx, param_env);
+ let mut checker = UnsafetyChecker::new(body, def, tcx, param_env);
checker.visit_body(&body);
- let unused_unsafes = (!tcx.is_typeck_child(def.did.to_def_id()))
- .then(|| check_unused_unsafe(tcx, def.did, &checker.used_unsafe_blocks));
+ let unused_unsafes = (!tcx.is_typeck_child(def.to_def_id()))
+ .then(|| check_unused_unsafe(tcx, def, &checker.used_unsafe_blocks));
tcx.arena.alloc(UnsafetyCheckResult {
violations: checker.violations,
@@ -527,21 +510,12 @@ fn unsafety_check_result(
fn report_unused_unsafe(tcx: TyCtxt<'_>, kind: UnusedUnsafe, id: HirId) {
let span = tcx.sess.source_map().guess_head_span(tcx.hir().span(id));
- let msg = "unnecessary `unsafe` block";
- tcx.struct_span_lint_hir(UNUSED_UNSAFE, id, span, msg, |lint| {
- lint.span_label(span, msg);
- match kind {
- UnusedUnsafe::Unused => {}
- UnusedUnsafe::InUnsafeBlock(id) => {
- lint.span_label(
- tcx.sess.source_map().guess_head_span(tcx.hir().span(id)),
- "because it's nested under this `unsafe` block",
- );
- }
- }
-
- lint
- });
+ let nested_parent = if let UnusedUnsafe::InUnsafeBlock(id) = kind {
+ Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
+ } else {
+ None
+ };
+ tcx.emit_spanned_lint(UNUSED_UNSAFE, id, span, errors::UnusedUnsafe { span, nested_parent });
}
pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
@@ -555,26 +529,11 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
let UnsafetyCheckResult { violations, unused_unsafes, .. } = tcx.unsafety_check_result(def_id);
for &UnsafetyViolation { source_info, lint_root, kind, details } in violations.iter() {
- let (description, note) = details.description_and_note();
+ let details = errors::RequiresUnsafeDetail { violation: details, span: source_info.span };
match kind {
UnsafetyViolationKind::General => {
- // once
- let unsafe_fn_msg = if unsafe_op_in_unsafe_fn_allowed(tcx, lint_root) {
- " function or"
- } else {
- ""
- };
-
- let mut err = struct_span_err!(
- tcx.sess,
- source_info.span,
- E0133,
- "{} is unsafe and requires unsafe{} block",
- description,
- unsafe_fn_msg,
- );
- err.span_label(source_info.span, description).note(note);
+ let op_in_unsafe_fn_allowed = unsafe_op_in_unsafe_fn_allowed(tcx, lint_root);
let note_non_inherited = tcx.hir().parent_iter(lint_root).find(|(id, node)| {
if let Node::Expr(block) = node
&& let ExprKind::Block(block, _) = block.kind
@@ -590,22 +549,23 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) {
false
}
});
- if let Some((id, _)) = note_non_inherited {
- let span = tcx.hir().span(id);
- err.span_label(
- tcx.sess.source_map().guess_head_span(span),
- "items do not inherit unsafety from separate enclosing items",
- );
- }
-
- err.emit();
+ let enclosing = if let Some((id, _)) = note_non_inherited {
+ Some(tcx.sess.source_map().guess_head_span(tcx.hir().span(id)))
+ } else {
+ None
+ };
+ tcx.sess.emit_err(errors::RequiresUnsafe {
+ span: source_info.span,
+ enclosing,
+ details,
+ op_in_unsafe_fn_allowed,
+ });
}
- UnsafetyViolationKind::UnsafeFn => tcx.struct_span_lint_hir(
+ UnsafetyViolationKind::UnsafeFn => tcx.emit_spanned_lint(
UNSAFE_OP_IN_UNSAFE_FN,
lint_root,
source_info.span,
- format!("{} is unsafe and requires unsafe block (error E0133)", description,),
- |lint| lint.span_label(source_info.span, description).note(note),
+ errors::UnsafeOpInUnsafeFn { details },
),
}
}
diff --git a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
index 0923824db..d435d3ee6 100644
--- a/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
+++ b/compiler/rustc_mir_transform/src/cleanup_post_borrowck.rs
@@ -24,7 +24,6 @@ impl<'tcx> MirPass<'tcx> for CleanupPostBorrowck {
for statement in basic_block.statements.iter_mut() {
match statement.kind {
StatementKind::AscribeUserType(..)
- | StatementKind::PlaceMention(..)
| StatementKind::Assign(box (_, Rvalue::Ref(_, BorrowKind::Shallow, _)))
| StatementKind::FakeRead(..) => statement.make_nop(),
_ => (),
diff --git a/compiler/rustc_mir_transform/src/const_debuginfo.rs b/compiler/rustc_mir_transform/src/const_debuginfo.rs
index 6f0ae4f07..f662ce645 100644
--- a/compiler/rustc_mir_transform/src/const_debuginfo.rs
+++ b/compiler/rustc_mir_transform/src/const_debuginfo.rs
@@ -10,19 +10,19 @@ use rustc_middle::{
};
use crate::MirPass;
-use rustc_index::{bit_set::BitSet, vec::IndexVec};
+use rustc_index::{bit_set::BitSet, IndexVec};
pub struct ConstDebugInfo;
impl<'tcx> MirPass<'tcx> for ConstDebugInfo {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- sess.opts.unstable_opts.unsound_mir_opts && sess.mir_opt_level() > 0
+ sess.mir_opt_level() > 0
}
fn run_pass(&self, _tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
trace!("running ConstDebugInfo on {:?}", body.source);
- for (local, constant) in find_optimization_oportunities(body) {
+ for (local, constant) in find_optimization_opportunities(body) {
for debuginfo in &mut body.var_debug_info {
if let VarDebugInfoContents::Place(p) = debuginfo.value {
if p.local == local && p.projection.is_empty() {
@@ -45,7 +45,7 @@ struct LocalUseVisitor {
local_assignment_locations: IndexVec<Local, Option<Location>>,
}
-fn find_optimization_oportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
+fn find_optimization_opportunities<'tcx>(body: &Body<'tcx>) -> Vec<(Local, Constant<'tcx>)> {
let mut visitor = LocalUseVisitor {
local_mutating_uses: IndexVec::from_elem(0, &body.local_decls),
local_assignment_locations: IndexVec::from_elem(None, &body.local_decls),
diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs
index 1bb45341e..1ba1951af 100644
--- a/compiler/rustc_mir_transform/src/const_prop.rs
+++ b/compiler/rustc_mir_transform/src/const_prop.rs
@@ -7,7 +7,7 @@ use rustc_const_eval::const_eval::CheckAlignment;
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::visit::{
MutVisitor, MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor,
};
@@ -18,13 +18,12 @@ use rustc_middle::ty::{self, ConstKind, Instance, ParamEnv, Ty, TyCtxt, TypeVisi
use rustc_span::{def_id::DefId, Span, DUMMY_SP};
use rustc_target::abi::{self, Align, HasDataLayout, Size, TargetDataLayout};
use rustc_target::spec::abi::Abi as CallAbi;
-use rustc_trait_selection::traits;
use crate::MirPass;
use rustc_const_eval::interpret::{
- self, compile_time_machine, AllocId, ConstAllocation, ConstValue, CtfeValidationMode, Frame,
- ImmTy, Immediate, InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer,
- Scalar, StackPopCleanup,
+ self, compile_time_machine, AllocId, ConstAllocation, ConstValue, Frame, ImmTy, Immediate,
+ InterpCx, InterpResult, LocalValue, MemoryKind, OpTy, PlaceTy, Pointer, Scalar,
+ StackPopCleanup,
};
/// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -84,42 +83,6 @@ impl<'tcx> MirPass<'tcx> for ConstProp {
return;
}
- // Check if it's even possible to satisfy the 'where' clauses
- // for this item.
- // This branch will never be taken for any normal function.
- // However, it's possible to `#!feature(trivial_bounds)]` to write
- // a function with impossible to satisfy clauses, e.g.:
- // `fn foo() where String: Copy {}`
- //
- // We don't usually need to worry about this kind of case,
- // since we would get a compilation error if the user tried
- // to call it. However, since we can do const propagation
- // even without any calls to the function, we need to make
- // sure that it even makes sense to try to evaluate the body.
- // If there are unsatisfiable where clauses, then all bets are
- // off, and we just give up.
- //
- // We manually filter the predicates, skipping anything that's not
- // "global". We are in a potentially generic context
- // (e.g. we are evaluating a function without substituting generic
- // parameters, so this filtering serves two purposes:
- //
- // 1. We skip evaluating any predicates that we would
- // never be able prove are unsatisfiable (e.g. `<T as Foo>`
- // 2. We avoid trying to normalize predicates involving generic
- // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
- // the normalization code (leading to cycle errors), since
- // it's usually never invoked in this way.
- let predicates = tcx
- .predicates_of(def_id.to_def_id())
- .predicates
- .iter()
- .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
- if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
- trace!("ConstProp skipped for {:?}: found unsatisfiable predicates", def_id);
- return;
- }
-
trace!("ConstProp starting for {:?}", def_id);
let dummy_body = &Body::new(
@@ -428,7 +391,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
/// Returns the value, if any, of evaluating `c`.
fn eval_constant(&mut self, c: &Constant<'tcx>) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176
- if c.needs_subst() {
+ if c.has_param() {
return None;
}
@@ -501,16 +464,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
return None;
}
- // Do not try creating references, nor any types with potentially-complex
- // invariants. This avoids an issue where checking validity would do a
- // bunch of work generating a nice message about the invariant violation,
- // only to not show it to anyone (since this isn't the lint).
- Rvalue::Cast(CastKind::Transmute, op, dst_ty) if !dst_ty.is_primitive() => {
- trace!("skipping Transmute of {:?} to {:?}", op, dst_ty);
-
- return None;
- }
-
// There's no other checking to do at this time.
Rvalue::Aggregate(..)
| Rvalue::Use(..)
@@ -527,7 +480,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
// FIXME we need to revisit this for #67176
- if rvalue.needs_subst() {
+ if rvalue.has_param() {
return None;
}
if !rvalue
@@ -628,18 +581,6 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
trace!("attempting to replace {:?} with {:?}", rval, value);
- if let Err(e) = self.ecx.const_validate_operand(
- value,
- vec![],
- // FIXME: is ref tracking too expensive?
- // FIXME: what is the point of ref tracking if we do not even check the tracked refs?
- &mut interpret::RefTracking::empty(),
- CtfeValidationMode::Regular,
- ) {
- trace!("validation error, attempt failed: {:?}", e);
- return;
- }
-
// FIXME> figure out what to do when read_immediate_raw fails
let imm = self.ecx.read_immediate_raw(value).ok();
@@ -773,13 +714,22 @@ impl CanConstProp {
}
}
-impl Visitor<'_> for CanConstProp {
+impl<'tcx> Visitor<'tcx> for CanConstProp {
+ fn visit_place(&mut self, place: &Place<'tcx>, mut context: PlaceContext, loc: Location) {
+ use rustc_middle::mir::visit::PlaceContext::*;
+
+ // Dereferencing just read the addess of `place.local`.
+ if place.projection.first() == Some(&PlaceElem::Deref) {
+ context = NonMutatingUse(NonMutatingUseContext::Copy);
+ }
+
+ self.visit_local(place.local, context, loc);
+ self.visit_projection(place.as_ref(), context, loc);
+ }
+
fn visit_local(&mut self, local: Local, context: PlaceContext, _: Location) {
use rustc_middle::mir::visit::PlaceContext::*;
match context {
- // Projections are fine, because `&mut foo.x` will be caught by
- // `MutatingUseContext::Borrow` elsewhere.
- MutatingUse(MutatingUseContext::Projection)
// These are just stores, where the storing is not propagatable, but there may be later
// mutations of the same local via `Store`
| MutatingUse(MutatingUseContext::Call)
@@ -810,7 +760,7 @@ impl Visitor<'_> for CanConstProp {
NonMutatingUse(NonMutatingUseContext::Copy)
| NonMutatingUse(NonMutatingUseContext::Move)
| NonMutatingUse(NonMutatingUseContext::Inspect)
- | NonMutatingUse(NonMutatingUseContext::Projection)
+ | NonMutatingUse(NonMutatingUseContext::PlaceMention)
| NonUse(_) => {}
// These could be propagated with a smarter analysis or just some careful thinking about
@@ -825,9 +775,11 @@ impl Visitor<'_> for CanConstProp {
| NonMutatingUse(NonMutatingUseContext::AddressOf)
| MutatingUse(MutatingUseContext::Borrow)
| MutatingUse(MutatingUseContext::AddressOf) => {
- trace!("local {:?} can't be propagaged because it's used: {:?}", local, context);
+ trace!("local {:?} can't be propagated because it's used: {:?}", local, context);
self.can_const_prop[local] = ConstPropMode::NoPropagation;
}
+ MutatingUse(MutatingUseContext::Projection)
+ | NonMutatingUse(NonMutatingUseContext::Projection) => bug!("visit_place should not pass {context:?} for {local:?}"),
}
}
}
@@ -853,6 +805,24 @@ impl<'tcx> MutVisitor<'tcx> for ConstPropagator<'_, 'tcx> {
}
}
+ fn process_projection_elem(
+ &mut self,
+ elem: PlaceElem<'tcx>,
+ _: Location,
+ ) -> Option<PlaceElem<'tcx>> {
+ if let PlaceElem::Index(local) = elem
+ && let Some(value) = self.get_const(local.into())
+ && self.should_const_prop(&value)
+ && let interpret::Operand::Immediate(interpret::Immediate::Scalar(scalar)) = *value
+ && let Ok(offset) = scalar.to_target_usize(&self.tcx)
+ && let Some(min_length) = offset.checked_add(1)
+ {
+ Some(PlaceElem::ConstantIndex { offset, min_length, from_end: false })
+ } else {
+ None
+ }
+ }
+
fn visit_assign(
&mut self,
place: &mut Place<'tcx>,
diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs
index 699fe4489..0fe49b8a1 100644
--- a/compiler/rustc_mir_transform/src/const_prop_lint.rs
+++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs
@@ -1,6 +1,8 @@
//! Propagates constants for early reporting of statically known
//! assertion failures
+use std::fmt::Debug;
+
use either::Left;
use rustc_const_eval::interpret::Immediate;
@@ -17,7 +19,6 @@ use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{
self, ConstInt, Instance, ParamEnv, ScalarInt, Ty, TyCtxt, TypeVisitableExt,
};
-use rustc_session::lint;
use rustc_span::Span;
use rustc_target::abi::{HasDataLayout, Size, TargetDataLayout};
use rustc_trait_selection::traits;
@@ -25,6 +26,7 @@ use rustc_trait_selection::traits;
use crate::const_prop::CanConstProp;
use crate::const_prop::ConstPropMachine;
use crate::const_prop::ConstPropMode;
+use crate::errors::AssertLint;
use crate::MirLint;
/// The maximum number of bytes that we'll allocate space for a local or the return value.
@@ -281,7 +283,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
/// Returns the value, if any, of evaluating `c`.
fn eval_constant(&mut self, c: &Constant<'tcx>, location: Location) -> Option<OpTy<'tcx>> {
// FIXME we need to revisit this for #67176
- if c.needs_subst() {
+ if c.has_param() {
return None;
}
@@ -311,18 +313,9 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
}
- fn report_assert_as_lint(
- &self,
- lint: &'static lint::Lint,
- location: Location,
- message: &'static str,
- panic: AssertKind<impl std::fmt::Debug>,
- ) {
- let source_info = self.body().source_info(location);
+ fn report_assert_as_lint(&self, source_info: &SourceInfo, lint: AssertLint<impl Debug>) {
if let Some(lint_root) = self.lint_root(*source_info) {
- self.tcx.struct_span_lint_hir(lint, lint_root, source_info.span, message, |lint| {
- lint.span_label(source_info.span, format!("{:?}", panic))
- });
+ self.tcx.emit_spanned_lint(lint.lint(), lint_root, source_info.span, lint);
}
}
@@ -335,11 +328,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// `AssertKind` only has an `OverflowNeg` variant, so make sure that is
// appropriate to use.
assert_eq!(op, UnOp::Neg, "Neg is the only UnOp that can overflow");
+ let source_info = self.body().source_info(location);
self.report_assert_as_lint(
- lint::builtin::ARITHMETIC_OVERFLOW,
- location,
- "this arithmetic operation will overflow",
- AssertKind::OverflowNeg(val.to_const_int()),
+ source_info,
+ AssertLint::ArithmeticOverflow(
+ source_info.span,
+ AssertKind::OverflowNeg(val.to_const_int()),
+ ),
);
return None;
}
@@ -368,25 +363,25 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let left_size = self.ecx.layout_of(left_ty).ok()?.size;
let right_size = r.layout.size;
let r_bits = r.to_scalar().to_bits(right_size).ok();
- if r_bits.map_or(false, |b| b >= left_size.bits() as u128) {
+ if r_bits.is_some_and(|b| b >= left_size.bits() as u128) {
debug!("check_binary_op: reporting assert for {:?}", location);
+ let source_info = self.body().source_info(location);
+ let panic = AssertKind::Overflow(
+ op,
+ match l {
+ Some(l) => l.to_const_int(),
+ // Invent a dummy value, the diagnostic ignores it anyway
+ None => ConstInt::new(
+ ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
+ left_ty.is_signed(),
+ left_ty.is_ptr_sized_integral(),
+ ),
+ },
+ r.to_const_int(),
+ );
self.report_assert_as_lint(
- lint::builtin::ARITHMETIC_OVERFLOW,
- location,
- "this arithmetic operation will overflow",
- AssertKind::Overflow(
- op,
- match l {
- Some(l) => l.to_const_int(),
- // Invent a dummy value, the diagnostic ignores it anyway
- None => ConstInt::new(
- ScalarInt::try_from_uint(1_u8, left_size).unwrap(),
- left_ty.is_signed(),
- left_ty.is_ptr_sized_integral(),
- ),
- },
- r.to_const_int(),
- ),
+ source_info,
+ AssertLint::ArithmeticOverflow(source_info.span, panic),
);
return None;
}
@@ -398,11 +393,13 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
let (_res, overflow, _ty) = this.ecx.overflowing_binary_op(op, &l, &r)?;
Ok(overflow)
})? {
+ let source_info = self.body().source_info(location);
self.report_assert_as_lint(
- lint::builtin::ARITHMETIC_OVERFLOW,
- location,
- "this arithmetic operation will overflow",
- AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+ source_info,
+ AssertLint::ArithmeticOverflow(
+ source_info.span,
+ AssertKind::Overflow(op, l.to_const_int(), r.to_const_int()),
+ ),
);
return None;
}
@@ -474,7 +471,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
}
// FIXME we need to revisit this for #67176
- if rvalue.needs_subst() {
+ if rvalue.has_param() {
return None;
}
if !rvalue.ty(self.local_decls(), self.tcx).is_sized(self.tcx, self.param_env) {
@@ -493,7 +490,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
cond: &Operand<'tcx>,
location: Location,
) -> Option<!> {
- let ref value = self.eval_operand(&cond, location)?;
+ let value = &self.eval_operand(&cond, location)?;
trace!("assertion on {:?} should be {:?}", value, expected);
let expected = Scalar::from_bool(expected);
@@ -543,11 +540,10 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> {
// Need proper const propagator for these.
_ => return None,
};
+ let source_info = self.body().source_info(location);
self.report_assert_as_lint(
- lint::builtin::UNCONDITIONAL_PANIC,
- location,
- "this operation will panic at runtime",
- msg,
+ source_info,
+ AssertLint::UnconditionalPanic(source_info.span, msg),
);
}
diff --git a/compiler/rustc_mir_transform/src/copy_prop.rs b/compiler/rustc_mir_transform/src/copy_prop.rs
index b571215f2..3df459dfa 100644
--- a/compiler/rustc_mir_transform/src/copy_prop.rs
+++ b/compiler/rustc_mir_transform/src/copy_prop.rs
@@ -1,5 +1,5 @@
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
@@ -33,9 +33,8 @@ impl<'tcx> MirPass<'tcx> for CopyProp {
}
fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
let borrowed_locals = borrowed_locals(body);
- let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
+ let ssa = SsaLocals::new(body);
let fully_moved = fully_moved_locals(&ssa, body);
debug!(?fully_moved);
@@ -76,7 +75,7 @@ fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
fn fully_moved_locals(ssa: &SsaLocals, body: &Body<'_>) -> BitSet<Local> {
let mut fully_moved = BitSet::new_filled(body.local_decls.len());
- for (_, rvalue) in ssa.assignments(body) {
+ for (_, rvalue, _) in ssa.assignments(body) {
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
= rvalue
else { continue };
@@ -162,20 +161,22 @@ impl<'tcx> MutVisitor<'tcx> for Replacer<'_, 'tcx> {
}
fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
- match stmt.kind {
- // When removing storage statements, we need to remove both (#107511).
- StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
- if self.storage_to_remove.contains(l) =>
- {
- stmt.make_nop()
- }
- StatementKind::Assign(box (ref place, ref mut rvalue))
- if place.as_local().is_some() =>
- {
- // Do not replace assignments.
- self.visit_rvalue(rvalue, loc)
- }
- _ => self.super_statement(stmt, loc),
+ // When removing storage statements, we need to remove both (#107511).
+ if let StatementKind::StorageLive(l) | StatementKind::StorageDead(l) = stmt.kind
+ && self.storage_to_remove.contains(l)
+ {
+ stmt.make_nop();
+ return
+ }
+
+ self.super_statement(stmt, loc);
+
+ // Do not leave tautological assignments around.
+ if let StatementKind::Assign(box (lhs, ref rhs)) = stmt.kind
+ && let Rvalue::Use(Operand::Copy(rhs) | Operand::Move(rhs)) | Rvalue::CopyForDeref(rhs) = *rhs
+ && lhs == rhs
+ {
+ stmt.make_nop();
}
}
}
diff --git a/compiler/rustc_mir_transform/src/coverage/debug.rs b/compiler/rustc_mir_transform/src/coverage/debug.rs
index 725883b83..6a3d42511 100644
--- a/compiler/rustc_mir_transform/src/coverage/debug.rs
+++ b/compiler/rustc_mir_transform/src/coverage/debug.rs
@@ -118,7 +118,7 @@ use rustc_middle::mir::spanview::{self, SpanViewable};
use rustc_data_structures::fx::FxHashMap;
use rustc_middle::mir::coverage::*;
-use rustc_middle::mir::{self, BasicBlock, TerminatorKind};
+use rustc_middle::mir::{self, BasicBlock};
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
@@ -292,10 +292,8 @@ impl DebugCounters {
}
pub fn some_block_label(&self, operand: ExpressionOperandId) -> Option<&String> {
- self.some_counters.as_ref().map_or(None, |counters| {
- counters
- .get(&operand)
- .map_or(None, |debug_counter| debug_counter.some_block_label.as_ref())
+ self.some_counters.as_ref().and_then(|counters| {
+ counters.get(&operand).and_then(|debug_counter| debug_counter.some_block_label.as_ref())
})
}
@@ -641,7 +639,7 @@ pub(super) fn dump_coverage_spanview<'tcx>(
let def_id = mir_source.def_id();
let span_viewables = span_viewables(tcx, mir_body, basic_coverage_blocks, &coverage_spans);
- let mut file = create_dump_file(tcx, "html", false, pass_name, &0, mir_body)
+ let mut file = create_dump_file(tcx, "html", false, pass_name, &0i32, mir_body)
.expect("Unexpected error creating MIR spanview HTML file");
let crate_name = tcx.crate_name(def_id.krate);
let item_name = tcx.def_path(def_id).to_filename_friendly_no_crate();
@@ -742,7 +740,7 @@ pub(super) fn dump_coverage_graphviz<'tcx>(
.join("\n ")
));
}
- let mut file = create_dump_file(tcx, "dot", false, pass_name, &0, mir_body)
+ let mut file = create_dump_file(tcx, "dot", false, pass_name, &0i32, mir_body)
.expect("Unexpected error creating BasicCoverageBlock graphviz DOT file");
graphviz_writer
.write_graphviz(tcx, &mut file)
@@ -798,7 +796,7 @@ fn bcb_to_string_sections<'tcx>(
}
let non_term_blocks = bcb_data.basic_blocks[0..len - 1]
.iter()
- .map(|&bb| format!("{:?}: {}", bb, term_type(&mir_body[bb].terminator().kind)))
+ .map(|&bb| format!("{:?}: {}", bb, mir_body[bb].terminator().kind.name()))
.collect::<Vec<_>>();
if non_term_blocks.len() > 0 {
sections.push(non_term_blocks.join("\n"));
@@ -806,28 +804,7 @@ fn bcb_to_string_sections<'tcx>(
sections.push(format!(
"{:?}: {}",
bcb_data.basic_blocks.last().unwrap(),
- term_type(&bcb_data.terminator(mir_body).kind)
+ bcb_data.terminator(mir_body).kind.name(),
));
sections
}
-
-/// Returns a simple string representation of a `TerminatorKind` variant, independent of any
-/// values it might hold.
-pub(super) fn term_type(kind: &TerminatorKind<'_>) -> &'static str {
- match kind {
- TerminatorKind::Goto { .. } => "Goto",
- TerminatorKind::SwitchInt { .. } => "SwitchInt",
- TerminatorKind::Resume => "Resume",
- TerminatorKind::Terminate => "Terminate",
- TerminatorKind::Return => "Return",
- TerminatorKind::Unreachable => "Unreachable",
- TerminatorKind::Drop { .. } => "Drop",
- TerminatorKind::Call { .. } => "Call",
- TerminatorKind::Assert { .. } => "Assert",
- TerminatorKind::Yield { .. } => "Yield",
- TerminatorKind::GeneratorDrop => "GeneratorDrop",
- TerminatorKind::FalseEdge { .. } => "FalseEdge",
- TerminatorKind::FalseUnwind { .. } => "FalseUnwind",
- TerminatorKind::InlineAsm { .. } => "InlineAsm",
- }
-}
diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs
index 7391a77b0..ea1223fbc 100644
--- a/compiler/rustc_mir_transform/src/coverage/graph.rs
+++ b/compiler/rustc_mir_transform/src/coverage/graph.rs
@@ -5,10 +5,11 @@ use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::dominators::{self, Dominators};
use rustc_data_structures::graph::{self, GraphSuccessors, WithNumNodes, WithStartNode};
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, BasicBlock, BasicBlockData, Terminator, TerminatorKind};
+use std::cmp::Ordering;
use std::ops::{Index, IndexMut};
const ID_SEPARATOR: &str = ",";
@@ -111,7 +112,7 @@ impl CoverageGraph {
if predecessors.len() > 1 {
"predecessors.len() > 1".to_owned()
} else {
- format!("bb {} is not in precessors: {:?}", bb.index(), predecessors)
+ format!("bb {} is not in predecessors: {:?}", bb.index(), predecessors)
}
);
}
@@ -212,8 +213,12 @@ impl CoverageGraph {
}
#[inline(always)]
- pub fn dominators(&self) -> &Dominators<BasicCoverageBlock> {
- self.dominators.as_ref().unwrap()
+ pub fn rank_partial_cmp(
+ &self,
+ a: BasicCoverageBlock,
+ b: BasicCoverageBlock,
+ ) -> Option<Ordering> {
+ self.dominators.as_ref().unwrap().rank_partial_cmp(a, b)
}
}
@@ -650,26 +655,6 @@ pub(super) fn find_loop_backedges(
let mut backedges = IndexVec::from_elem_n(Vec::<BasicCoverageBlock>::new(), num_bcbs);
// Identify loops by their backedges.
- //
- // The computational complexity is bounded by: n(s) x d where `n` is the number of
- // `BasicCoverageBlock` nodes (the simplified/reduced representation of the CFG derived from the
- // MIR); `s` is the average number of successors per node (which is most likely less than 2, and
- // independent of the size of the function, so it can be treated as a constant);
- // and `d` is the average number of dominators per node.
- //
- // The average number of dominators depends on the size and complexity of the function, and
- // nodes near the start of the function's control flow graph typically have less dominators
- // than nodes near the end of the CFG. Without doing a detailed mathematical analysis, I
- // think the resulting complexity has the characteristics of O(n log n).
- //
- // The overall complexity appears to be comparable to many other MIR transform algorithms, and I
- // don't expect that this function is creating a performance hot spot, but if this becomes an
- // issue, there may be ways to optimize the `dominates` algorithm (as indicated by an
- // existing `FIXME` comment in that code), or possibly ways to optimize it's usage here, perhaps
- // by keeping track of results for visited `BasicCoverageBlock`s if they can be used to short
- // circuit downstream `dominates` checks.
- //
- // For now, that kind of optimization seems unnecessarily complicated.
for (bcb, _) in basic_coverage_blocks.iter_enumerated() {
for &successor in &basic_coverage_blocks.successors[bcb] {
if basic_coverage_blocks.dominates(successor, bcb) {
diff --git a/compiler/rustc_mir_transform/src/coverage/mod.rs b/compiler/rustc_mir_transform/src/coverage/mod.rs
index 5ecb2d6a6..076e714d7 100644
--- a/compiler/rustc_mir_transform/src/coverage/mod.rs
+++ b/compiler/rustc_mir_transform/src/coverage/mod.rs
@@ -16,7 +16,7 @@ use crate::MirPass;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::sync::Lrc;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::hir;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::mir::coverage::*;
@@ -514,7 +514,7 @@ fn make_code_region(
// Extend an empty span by one character so the region will be counted.
let CharPos(char_pos) = start_col;
if span.hi() == body_span.hi() {
- start_col = CharPos(char_pos - 1);
+ start_col = CharPos(char_pos.saturating_sub(1));
} else {
end_col = CharPos(char_pos + 1);
}
@@ -577,5 +577,10 @@ fn get_body_span<'tcx>(
fn hash_mir_source<'tcx>(tcx: TyCtxt<'tcx>, hir_body: &'tcx rustc_hir::Body<'tcx>) -> u64 {
// FIXME(cjgillot) Stop hashing HIR manually here.
let owner = hir_body.id().hir_id.owner;
- tcx.hir_owner_nodes(owner).unwrap().opt_hash_including_bodies.unwrap().to_smaller_hash()
+ tcx.hir_owner_nodes(owner)
+ .unwrap()
+ .opt_hash_including_bodies
+ .unwrap()
+ .to_smaller_hash()
+ .as_u64()
}
diff --git a/compiler/rustc_mir_transform/src/coverage/query.rs b/compiler/rustc_mir_transform/src/coverage/query.rs
index 3bd7f31b4..74b4b4a07 100644
--- a/compiler/rustc_mir_transform/src/coverage/query.rs
+++ b/compiler/rustc_mir_transform/src/coverage/query.rs
@@ -2,7 +2,7 @@ use super::*;
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::{self, Body, Coverage, CoverageInfo};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_span::def_id::DefId;
@@ -164,7 +164,6 @@ fn is_inlined(body: &Body<'_>, statement: &Statement<'_>) -> bool {
/// whether that means const mir or runtime mir. For `const fn` this opts for runtime
/// mir.
fn mir_body(tcx: TyCtxt<'_>, def_id: DefId) -> &mir::Body<'_> {
- let id = ty::WithOptConstParam::unknown(def_id);
- let def = ty::InstanceDef::Item(id);
+ let def = ty::InstanceDef::Item(def_id);
tcx.instance_mir(def)
}
diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs
index 287ae2170..d27200419 100644
--- a/compiler/rustc_mir_transform/src/coverage/spans.rs
+++ b/compiler/rustc_mir_transform/src/coverage/spans.rs
@@ -1,4 +1,3 @@
-use super::debug::term_type;
use super::graph::{BasicCoverageBlock, BasicCoverageBlockData, CoverageGraph, START_BCB};
use itertools::Itertools;
@@ -40,7 +39,7 @@ impl CoverageStatement {
"{}: @{}.{}: {:?}",
source_range_no_file(tcx, span),
bb.index(),
- term_type(&term.kind),
+ term.kind.name(),
term.kind
)
}
@@ -345,7 +344,7 @@ impl<'a, 'tcx> CoverageSpans<'a, 'tcx> {
// before the dominated equal spans). When later comparing two spans in
// order, the first will either dominate the second, or they will have no
// dominator relationship.
- self.basic_coverage_blocks.dominators().rank_partial_cmp(a.bcb, b.bcb)
+ self.basic_coverage_blocks.rank_partial_cmp(a.bcb, b.bcb)
}
} else {
// Sort hi() in reverse order so shorter spans are attempted after longer spans.
diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs
index 0f6c06e37..90b58933d 100644
--- a/compiler/rustc_mir_transform/src/coverage/tests.rs
+++ b/compiler/rustc_mir_transform/src/coverage/tests.rs
@@ -25,7 +25,6 @@
//! to: `rustc_span::create_default_session_globals_then(|| { test_here(); })`.
use super::counters;
-use super::debug;
use super::graph;
use super::spans;
@@ -34,7 +33,7 @@ use coverage_test_macros::let_bcb;
use itertools::Itertools;
use rustc_data_structures::graph::WithNumNodes;
use rustc_data_structures::graph::WithSuccessors;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::coverage::CoverageKind;
use rustc_middle::mir::*;
use rustc_middle::ty;
@@ -188,12 +187,12 @@ fn debug_basic_blocks(mir_body: &Body<'_>) -> String {
| TerminatorKind::Goto { target }
| TerminatorKind::InlineAsm { destination: Some(target), .. }
| TerminatorKind::Yield { resume: target, .. } => {
- format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), target)
+ format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), target)
}
TerminatorKind::SwitchInt { targets, .. } => {
- format!("{}{:?}:{} -> {:?}", sp, bb, debug::term_type(kind), targets)
+ format!("{}{:?}:{} -> {:?}", sp, bb, kind.name(), targets)
}
- _ => format!("{}{:?}:{}", sp, bb, debug::term_type(kind)),
+ _ => format!("{}{:?}:{}", sp, bb, kind.name()),
}
})
.collect::<Vec<_>>()
@@ -215,7 +214,7 @@ fn print_mir_graphviz(name: &str, mir_body: &Body<'_>) {
" {:?} [label=\"{:?}: {}\"];\n{}",
bb,
bb,
- debug::term_type(&data.terminator().kind),
+ data.terminator().kind.name(),
mir_body
.basic_blocks
.successors(bb)
@@ -244,7 +243,7 @@ fn print_coverage_graphviz(
" {:?} [label=\"{:?}: {}\"];\n{}",
bcb,
bcb,
- debug::term_type(&bcb_data.terminator(mir_body).kind),
+ bcb_data.terminator(mir_body).kind.name(),
basic_coverage_blocks
.successors(bcb)
.map(|successor| { format!(" {:?} -> {:?};", bcb, successor) })
diff --git a/compiler/rustc_mir_transform/src/ctfe_limit.rs b/compiler/rustc_mir_transform/src/ctfe_limit.rs
index 1b3ac78fb..bf5722b3d 100644
--- a/compiler/rustc_mir_transform/src/ctfe_limit.rs
+++ b/compiler/rustc_mir_transform/src/ctfe_limit.rs
@@ -47,7 +47,7 @@ fn has_back_edge(
return false;
}
// Check if any of the dominators of the node are also the node's successor.
- doms.dominators(node).any(|dom| node_data.terminator().successors().any(|succ| succ == dom))
+ node_data.terminator().successors().any(|succ| doms.dominates(succ, node))
}
fn insert_counter(basic_block_data: &mut BasicBlockData<'_>) {
diff --git a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
index d4db7e2de..7adfc9dff 100644
--- a/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
+++ b/compiler/rustc_mir_transform/src/dataflow_const_prop.rs
@@ -70,22 +70,6 @@ struct ConstAnalysis<'a, 'tcx> {
param_env: ty::ParamEnv<'tcx>,
}
-impl<'tcx> ConstAnalysis<'_, 'tcx> {
- fn eval_discriminant(
- &self,
- enum_ty: Ty<'tcx>,
- variant_index: VariantIdx,
- ) -> Option<ScalarTy<'tcx>> {
- if !enum_ty.is_enum() {
- return None;
- }
- let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
- let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
- let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?;
- Some(ScalarTy(discr_value, discr.ty))
- }
-}
-
impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
type Value = FlatSet<ScalarTy<'tcx>>;
@@ -95,22 +79,22 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
&self.map
}
- fn handle_statement(&self, statement: &Statement<'tcx>, state: &mut State<Self::Value>) {
- match statement.kind {
- StatementKind::SetDiscriminant { box ref place, variant_index } => {
- state.flood_discr(place.as_ref(), &self.map);
- if self.map.find_discr(place.as_ref()).is_some() {
- let enum_ty = place.ty(self.local_decls, self.tcx).ty;
- if let Some(discr) = self.eval_discriminant(enum_ty, variant_index) {
- state.assign_discr(
- place.as_ref(),
- ValueOrPlace::Value(FlatSet::Elem(discr)),
- &self.map,
- );
- }
- }
+ fn handle_set_discriminant(
+ &self,
+ place: Place<'tcx>,
+ variant_index: VariantIdx,
+ state: &mut State<Self::Value>,
+ ) {
+ state.flood_discr(place.as_ref(), &self.map);
+ if self.map.find_discr(place.as_ref()).is_some() {
+ let enum_ty = place.ty(self.local_decls, self.tcx).ty;
+ if let Some(discr) = self.eval_discriminant(enum_ty, variant_index) {
+ state.assign_discr(
+ place.as_ref(),
+ ValueOrPlace::Value(FlatSet::Elem(discr)),
+ &self.map,
+ );
}
- _ => self.super_statement(statement, state),
}
}
@@ -126,59 +110,55 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
// we must make sure that all `target as Variant#i` are `Top`.
state.flood(target.as_ref(), self.map());
- if let Some(target_idx) = self.map().find(target.as_ref()) {
- let (variant_target, variant_index) = match **kind {
- AggregateKind::Tuple | AggregateKind::Closure(..) => {
- (Some(target_idx), None)
- }
- AggregateKind::Adt(def_id, variant_index, ..) => {
- match self.tcx.def_kind(def_id) {
- DefKind::Struct => (Some(target_idx), None),
- DefKind::Enum => (
- self.map.apply(target_idx, TrackElem::Variant(variant_index)),
- Some(variant_index),
- ),
- _ => (None, None),
- }
- }
- _ => (None, None),
- };
- if let Some(variant_target_idx) = variant_target {
- for (field_index, operand) in operands.iter().enumerate() {
- if let Some(field) = self.map().apply(
- variant_target_idx,
- TrackElem::Field(FieldIdx::from_usize(field_index)),
- ) {
- let result = self.handle_operand(operand, state);
- state.insert_idx(field, result, self.map());
- }
+ let Some(target_idx) = self.map().find(target.as_ref()) else { return };
+
+ let (variant_target, variant_index) = match **kind {
+ AggregateKind::Tuple | AggregateKind::Closure(..) => (Some(target_idx), None),
+ AggregateKind::Adt(def_id, variant_index, ..) => {
+ match self.tcx.def_kind(def_id) {
+ DefKind::Struct => (Some(target_idx), None),
+ DefKind::Enum => (
+ self.map.apply(target_idx, TrackElem::Variant(variant_index)),
+ Some(variant_index),
+ ),
+ _ => return,
}
}
- if let Some(variant_index) = variant_index
- && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant)
- {
- // We are assigning the discriminant as part of an aggregate.
- // This discriminant can only alias a variant field's value if the operand
- // had an invalid value for that type.
- // Using invalid values is UB, so we are allowed to perform the assignment
- // without extra flooding.
- let enum_ty = target.ty(self.local_decls, self.tcx).ty;
- if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) {
- state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map);
+ _ => return,
+ };
+ if let Some(variant_target_idx) = variant_target {
+ for (field_index, operand) in operands.iter().enumerate() {
+ if let Some(field) = self.map().apply(
+ variant_target_idx,
+ TrackElem::Field(FieldIdx::from_usize(field_index)),
+ ) {
+ let result = self.handle_operand(operand, state);
+ state.insert_idx(field, result, self.map());
}
}
}
+ if let Some(variant_index) = variant_index
+ && let Some(discr_idx) = self.map().apply(target_idx, TrackElem::Discriminant)
+ {
+ // We are assigning the discriminant as part of an aggregate.
+ // This discriminant can only alias a variant field's value if the operand
+ // had an invalid value for that type.
+ // Using invalid values is UB, so we are allowed to perform the assignment
+ // without extra flooding.
+ let enum_ty = target.ty(self.local_decls, self.tcx).ty;
+ if let Some(discr_val) = self.eval_discriminant(enum_ty, variant_index) {
+ state.insert_value_idx(discr_idx, FlatSet::Elem(discr_val), &self.map);
+ }
+ }
}
Rvalue::CheckedBinaryOp(op, box (left, right)) => {
// Flood everything now, so we can use `insert_value_idx` directly later.
state.flood(target.as_ref(), self.map());
- let target = self.map().find(target.as_ref());
+ let Some(target) = self.map().find(target.as_ref()) else { return };
- let value_target = target
- .and_then(|target| self.map().apply(target, TrackElem::Field(0_u32.into())));
- let overflow_target = target
- .and_then(|target| self.map().apply(target, TrackElem::Field(1_u32.into())));
+ let value_target = self.map().apply(target, TrackElem::Field(0_u32.into()));
+ let overflow_target = self.map().apply(target, TrackElem::Field(1_u32.into()));
if value_target.is_some() || overflow_target.is_some() {
let (val, overflow) = self.binary_op(state, *op, left, right);
@@ -228,8 +208,8 @@ impl<'tcx> ValueAnalysis<'tcx> for ConstAnalysis<'_, 'tcx> {
_ => unreachable!(),
}
.map(|result| ValueOrPlace::Value(self.wrap_immediate(result, *ty)))
- .unwrap_or(ValueOrPlace::top()),
- _ => ValueOrPlace::top(),
+ .unwrap_or(ValueOrPlace::TOP),
+ _ => ValueOrPlace::TOP,
},
Rvalue::BinaryOp(op, box (left, right)) => {
// Overflows must be ignored here.
@@ -323,7 +303,7 @@ impl<'tcx> std::fmt::Debug for ScalarTy<'tcx> {
impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
pub fn new(tcx: TyCtxt<'tcx>, body: &'a Body<'tcx>, map: Map) -> Self {
- let param_env = tcx.param_env(body.source.def_id());
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
Self {
map,
tcx,
@@ -351,7 +331,7 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
}
(FlatSet::Bottom, _) | (_, FlatSet::Bottom) => (FlatSet::Bottom, FlatSet::Bottom),
(_, _) => {
- // Could attempt some algebraic simplifcations here.
+ // Could attempt some algebraic simplifications here.
(FlatSet::Top, FlatSet::Top)
}
}
@@ -377,6 +357,20 @@ impl<'a, 'tcx> ConstAnalysis<'a, 'tcx> {
}
}
+ fn eval_discriminant(
+ &self,
+ enum_ty: Ty<'tcx>,
+ variant_index: VariantIdx,
+ ) -> Option<ScalarTy<'tcx>> {
+ if !enum_ty.is_enum() {
+ return None;
+ }
+ let discr = enum_ty.discriminant_for_variant(self.tcx, variant_index)?;
+ let discr_layout = self.tcx.layout_of(self.param_env.and(discr.ty)).ok()?;
+ let discr_value = Scalar::try_from_uint(discr.val, discr_layout.size)?;
+ Some(ScalarTy(discr_value, discr.ty))
+ }
+
fn wrap_scalar(&self, scalar: Scalar, ty: Ty<'tcx>) -> FlatSet<ScalarTy<'tcx>> {
FlatSet::Elem(ScalarTy(scalar, ty))
}
@@ -520,21 +514,6 @@ impl<'tcx, 'map, 'a> Visitor<'tcx> for OperandCollector<'tcx, 'map, 'a> {
_ => (),
}
}
-
- fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) {
- match rvalue {
- Rvalue::Discriminant(place) => {
- match self.state.get_discr(place.as_ref(), self.visitor.map) {
- FlatSet::Top => (),
- FlatSet::Elem(value) => {
- self.visitor.before_effect.insert((location, *place), value);
- }
- FlatSet::Bottom => (),
- }
- }
- _ => self.super_rvalue(rvalue, location),
- }
- }
}
struct DummyMachine;
diff --git a/compiler/rustc_mir_transform/src/dead_store_elimination.rs b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
index 18c407b42..7bc5183a0 100644
--- a/compiler/rustc_mir_transform/src/dead_store_elimination.rs
+++ b/compiler/rustc_mir_transform/src/dead_store_elimination.rs
@@ -54,11 +54,10 @@ pub fn eliminate<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>, borrowed: &BitS
| StatementKind::Coverage(_)
| StatementKind::Intrinsic(_)
| StatementKind::ConstEvalCounter
+ | StatementKind::PlaceMention(_)
| StatementKind::Nop => (),
- StatementKind::FakeRead(_)
- | StatementKind::PlaceMention(_)
- | StatementKind::AscribeUserType(_, _) => {
+ StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
bug!("{:?} not found in this MIR phase!", &statement.kind)
}
}
diff --git a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
index e5c3fa564..a133c9d47 100644
--- a/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
+++ b/compiler/rustc_mir_transform/src/deduce_param_attrs.rs
@@ -8,8 +8,8 @@
use rustc_hir::def_id::LocalDefId;
use rustc_index::bit_set::BitSet;
use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor};
-use rustc_middle::mir::{Body, Local, Location, Operand, Terminator, TerminatorKind, RETURN_PLACE};
-use rustc_middle::ty::{self, DeducedParamAttrs, ParamEnv, Ty, TyCtxt};
+use rustc_middle::mir::{Body, Location, Operand, Place, Terminator, TerminatorKind, RETURN_PLACE};
+use rustc_middle::ty::{self, DeducedParamAttrs, Ty, TyCtxt};
use rustc_session::config::OptLevel;
/// A visitor that determines which arguments have been mutated. We can't use the mutability field
@@ -29,31 +29,31 @@ impl DeduceReadOnly {
}
impl<'tcx> Visitor<'tcx> for DeduceReadOnly {
- fn visit_local(&mut self, local: Local, mut context: PlaceContext, _: Location) {
+ fn visit_place(&mut self, place: &Place<'tcx>, context: PlaceContext, _location: Location) {
// We're only interested in arguments.
- if local == RETURN_PLACE || local.index() > self.mutable_args.domain_size() {
+ if place.local == RETURN_PLACE || place.local.index() > self.mutable_args.domain_size() {
return;
}
- // Replace place contexts that are moves with copies. This is safe in all cases except
- // function argument position, which we already handled in `visit_terminator()` by using the
- // ArgumentChecker. See the comment in that method for more details.
- //
- // In the future, we might want to move this out into a separate pass, but for now let's
- // just do it on the fly because that's faster.
- if matches!(context, PlaceContext::NonMutatingUse(NonMutatingUseContext::Move)) {
- context = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
- }
-
- match context {
- PlaceContext::MutatingUse(..)
- | PlaceContext::NonMutatingUse(NonMutatingUseContext::Move) => {
+ let mark_as_mutable = match context {
+ PlaceContext::MutatingUse(..) => {
// This is a mutation, so mark it as such.
- self.mutable_args.insert(local.index() - 1);
+ true
+ }
+ PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf) => {
+ // Whether mutating though a `&raw const` is allowed is still undecided, so we
+ // disable any sketchy `readonly` optimizations for now.
+ // But we only need to do this if the pointer would point into the argument.
+ !place.is_indirect()
}
PlaceContext::NonMutatingUse(..) | PlaceContext::NonUse(..) => {
// Not mutating, so it's fine.
+ false
}
+ };
+
+ if mark_as_mutable {
+ self.mutable_args.insert(place.local.index() - 1);
}
}
@@ -198,11 +198,12 @@ pub fn deduced_param_attrs<'tcx>(
// see [1].
//
// [1]: https://github.com/rust-lang/rust/pull/103172#discussion_r999139997
+ let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut deduced_param_attrs = tcx.arena.alloc_from_iter(
body.local_decls.iter().skip(1).take(body.arg_count).enumerate().map(
|(arg_index, local_decl)| DeducedParamAttrs {
read_only: !deduce_read_only.mutable_args.contains(arg_index)
- && local_decl.ty.is_freeze(tcx, ParamEnv::reveal_all()),
+ && local_decl.ty.is_freeze(tcx, param_env),
},
),
);
diff --git a/compiler/rustc_mir_transform/src/deref_separator.rs b/compiler/rustc_mir_transform/src/deref_separator.rs
index b8a5b92be..a39026751 100644
--- a/compiler/rustc_mir_transform/src/deref_separator.rs
+++ b/compiler/rustc_mir_transform/src/deref_separator.rs
@@ -1,5 +1,5 @@
use crate::MirPass;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::visit::NonUseContext::VarDebugInfo;
use rustc_middle::mir::visit::{MutVisitor, PlaceContext};
diff --git a/compiler/rustc_mir_transform/src/dest_prop.rs b/compiler/rustc_mir_transform/src/dest_prop.rs
index 391649177..78758e2db 100644
--- a/compiler/rustc_mir_transform/src/dest_prop.rs
+++ b/compiler/rustc_mir_transform/src/dest_prop.rs
@@ -69,7 +69,7 @@
//! of this is that such liveness analysis can report more accurate results about whole locals at
//! a time. For example, consider:
//!
-//! ```ignore (syntax-highliting-only)
+//! ```ignore (syntax-highlighting-only)
//! _1 = u;
//! // unrelated code
//! _1.f1 = v;
@@ -360,7 +360,7 @@ struct FilterInformation<'a, 'body, 'alloc, 'tcx> {
}
// We first implement some utility functions which we will expose removing candidates according to
-// different needs. Throughout the livenss filtering, the `candidates` are only ever accessed
+// different needs. Throughout the liveness filtering, the `candidates` are only ever accessed
// through these methods, and not directly.
impl<'alloc> Candidates<'alloc> {
/// Just `Vec::retain`, but the condition is inverted and we add debugging output
@@ -582,10 +582,9 @@ impl WriteInfo {
| StatementKind::Nop
| StatementKind::Coverage(_)
| StatementKind::StorageLive(_)
- | StatementKind::StorageDead(_) => (),
- StatementKind::FakeRead(_)
- | StatementKind::AscribeUserType(_, _)
- | StatementKind::PlaceMention(_) => {
+ | StatementKind::StorageDead(_)
+ | StatementKind::PlaceMention(_) => (),
+ StatementKind::FakeRead(_) | StatementKind::AscribeUserType(_, _) => {
bug!("{:?} not found in this MIR phase", statement)
}
}
diff --git a/compiler/rustc_mir_transform/src/dump_mir.rs b/compiler/rustc_mir_transform/src/dump_mir.rs
index 594cbd897..746e3d965 100644
--- a/compiler/rustc_mir_transform/src/dump_mir.rs
+++ b/compiler/rustc_mir_transform/src/dump_mir.rs
@@ -12,7 +12,7 @@ use rustc_session::config::OutputType;
pub struct Marker(pub &'static str);
impl<'tcx> MirPass<'tcx> for Marker {
- fn name(&self) -> &str {
+ fn name(&self) -> &'static str {
self.0
}
diff --git a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
index 856234994..f31653caa 100644
--- a/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_box_derefs.rs
@@ -4,7 +4,7 @@
use crate::MirPass;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::visit::MutVisitor;
use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/elaborate_drops.rs b/compiler/rustc_mir_transform/src/elaborate_drops.rs
index a702113bd..fda0e1023 100644
--- a/compiler/rustc_mir_transform/src/elaborate_drops.rs
+++ b/compiler/rustc_mir_transform/src/elaborate_drops.rs
@@ -1,7 +1,7 @@
use crate::deref_separator::deref_finder;
use crate::MirPass;
-use rustc_data_structures::fx::FxHashMap;
use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
@@ -14,7 +14,7 @@ use rustc_mir_dataflow::un_derefer::UnDerefer;
use rustc_mir_dataflow::MoveDataParamEnv;
use rustc_mir_dataflow::{on_all_children_bits, on_all_drop_children_bits};
use rustc_mir_dataflow::{Analysis, ResultsCursor};
-use rustc_span::{DesugaringKind, Span};
+use rustc_span::Span;
use rustc_target::abi::{FieldIdx, VariantIdx};
use std::fmt;
@@ -24,7 +24,7 @@ use std::fmt;
/// In general, the compiler cannot determine at compile time whether a destructor will run or not.
///
/// At a high level, this pass refines Drop to only run the destructor if the
-/// target is initialized. The way this is achievied is by inserting drop flags for every variable
+/// target is initialized. The way this is achieved is by inserting drop flags for every variable
/// that may be dropped, and then using those flags to determine whether a destructor should run.
/// Once this is complete, Drop terminators in the MIR correspond to a call to the "drop glue" or
/// "drop shim" for the type of the dropped place.
@@ -84,12 +84,13 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops {
let reachable = traversal::reachable_as_bitset(body);
+ let drop_flags = IndexVec::from_elem(None, &env.move_data.move_paths);
ElaborateDropsCtxt {
tcx,
body,
env: &env,
init_data: InitializationData { inits, uninits },
- drop_flags: Default::default(),
+ drop_flags,
patch: MirPatch::new(body),
un_derefer: un_derefer,
reachable,
@@ -293,7 +294,7 @@ struct ElaborateDropsCtxt<'a, 'tcx> {
body: &'a Body<'tcx>,
env: &'a MoveDataParamEnv<'tcx>,
init_data: InitializationData<'a, 'tcx>,
- drop_flags: FxHashMap<MovePathIndex, Local>,
+ drop_flags: IndexVec<MovePathIndex, Option<Local>>,
patch: MirPatch<'tcx>,
un_derefer: UnDerefer<'tcx>,
reachable: BitSet<BasicBlock>,
@@ -312,11 +313,11 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let tcx = self.tcx;
let patch = &mut self.patch;
debug!("create_drop_flag({:?})", self.body.span);
- self.drop_flags.entry(index).or_insert_with(|| patch.new_internal(tcx.types.bool, span));
+ self.drop_flags[index].get_or_insert_with(|| patch.new_internal(tcx.types.bool, span));
}
fn drop_flag(&mut self, index: MovePathIndex) -> Option<Place<'tcx>> {
- self.drop_flags.get(&index).map(|t| Place::from(*t))
+ self.drop_flags[index].map(Place::from)
}
/// create a patch that elaborates all drops in the input
@@ -365,7 +366,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
if maybe_dead {
self.tcx.sess.delay_span_bug(
terminator.source_info.span,
- &format!(
+ format!(
"drop of untracked, uninitialized value {:?}, place {:?} ({:?})",
bb, place, path
),
@@ -400,7 +401,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let terminator = data.terminator();
match terminator.kind {
- TerminatorKind::Drop { mut place, target, unwind } => {
+ TerminatorKind::Drop { mut place, target, unwind, replace } => {
if let Some(new_place) = self.un_derefer.derefer(place.as_ref(), self.body) {
place = new_place;
}
@@ -433,13 +434,10 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
)
}
LookupResult::Parent(..) => {
- if !matches!(
- terminator.source_info.span.desugaring_kind(),
- Some(DesugaringKind::Replace),
- ) {
+ if !replace {
self.tcx.sess.delay_span_bug(
terminator.source_info.span,
- &format!("drop of untracked value {:?}", bb),
+ format!("drop of untracked value {:?}", bb),
);
}
// A drop and replace behind a pointer/array/whatever.
@@ -463,7 +461,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
}
fn set_drop_flag(&mut self, loc: Location, path: MovePathIndex, val: DropFlagState) {
- if let Some(&flag) = self.drop_flags.get(&path) {
+ if let Some(flag) = self.drop_flags[path] {
let span = self.patch.source_info_for_location(self.body, loc).span;
let val = self.constant_bool(span, val.value());
self.patch.add_assign(loc, Place::from(flag), val);
@@ -474,7 +472,7 @@ impl<'b, 'tcx> ElaborateDropsCtxt<'b, 'tcx> {
let loc = Location::START;
let span = self.patch.source_info_for_location(self.body, loc).span;
let false_ = self.constant_bool(span, false);
- for flag in self.drop_flags.values() {
+ for flag in self.drop_flags.iter().flatten() {
self.patch.add_assign(loc, Place::from(*flag), false_.clone());
}
}
diff --git a/compiler/rustc_mir_transform/src/errors.rs b/compiler/rustc_mir_transform/src/errors.rs
new file mode 100644
index 000000000..602e40d51
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/errors.rs
@@ -0,0 +1,245 @@
+use rustc_errors::{
+ DecorateLint, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Handler, IntoDiagnostic,
+};
+use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
+use rustc_middle::mir::{AssertKind, UnsafetyViolationDetails};
+use rustc_session::lint::{self, Lint};
+use rustc_span::Span;
+
+#[derive(LintDiagnostic)]
+pub(crate) enum ConstMutate {
+ #[diag(mir_transform_const_modify)]
+ #[note]
+ Modify {
+ #[note(mir_transform_const_defined_here)]
+ konst: Span,
+ },
+ #[diag(mir_transform_const_mut_borrow)]
+ #[note]
+ #[note(mir_transform_note2)]
+ MutBorrow {
+ #[note(mir_transform_note3)]
+ method_call: Option<Span>,
+ #[note(mir_transform_const_defined_here)]
+ konst: Span,
+ },
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_unaligned_packed_ref, code = "E0793")]
+#[note]
+#[note(mir_transform_note_ub)]
+#[help]
+pub(crate) struct UnalignedPackedRef {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_unused_unsafe)]
+pub(crate) struct UnusedUnsafe {
+ #[label(mir_transform_unused_unsafe)]
+ pub span: Span,
+ #[label]
+ pub nested_parent: Option<Span>,
+}
+
+pub(crate) struct RequiresUnsafe {
+ pub span: Span,
+ pub details: RequiresUnsafeDetail,
+ pub enclosing: Option<Span>,
+ pub op_in_unsafe_fn_allowed: bool,
+}
+
+// The primary message for this diagnostic should be '{$label} is unsafe and...',
+// so we need to eagerly translate the label here, which isn't supported by the derive API
+// We could also exhaustively list out the primary messages for all unsafe violations,
+// but this would result in a lot of duplication.
+impl<'sess, G: EmissionGuarantee> IntoDiagnostic<'sess, G> for RequiresUnsafe {
+ #[track_caller]
+ fn into_diagnostic(self, handler: &'sess Handler) -> DiagnosticBuilder<'sess, G> {
+ let mut diag =
+ handler.struct_diagnostic(crate::fluent_generated::mir_transform_requires_unsafe);
+ diag.code(rustc_errors::DiagnosticId::Error("E0133".to_string()));
+ diag.set_span(self.span);
+ diag.span_label(self.span, self.details.label());
+ diag.note(self.details.note());
+ let desc = handler.eagerly_translate_to_string(self.details.label(), [].into_iter());
+ diag.set_arg("details", desc);
+ diag.set_arg("op_in_unsafe_fn_allowed", self.op_in_unsafe_fn_allowed);
+ if let Some(sp) = self.enclosing {
+ diag.span_label(sp, crate::fluent_generated::mir_transform_not_inherited);
+ }
+ diag
+ }
+}
+
+#[derive(Copy, Clone)]
+pub(crate) struct RequiresUnsafeDetail {
+ pub span: Span,
+ pub violation: UnsafetyViolationDetails,
+}
+
+impl RequiresUnsafeDetail {
+ fn note(self) -> DiagnosticMessage {
+ use UnsafetyViolationDetails::*;
+ match self.violation {
+ CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_note,
+ UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_note,
+ InitializingTypeWith => {
+ crate::fluent_generated::mir_transform_initializing_valid_range_note
+ }
+ CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_note,
+ UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_note,
+ UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_note,
+ DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_note,
+ AccessToUnionField => crate::fluent_generated::mir_transform_union_access_note,
+ MutationOfLayoutConstrainedField => {
+ crate::fluent_generated::mir_transform_mutation_layout_constrained_note
+ }
+ BorrowOfLayoutConstrainedField => {
+ crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_note
+ }
+ CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_note,
+ }
+ }
+
+ fn label(self) -> DiagnosticMessage {
+ use UnsafetyViolationDetails::*;
+ match self.violation {
+ CallToUnsafeFunction => crate::fluent_generated::mir_transform_call_to_unsafe_label,
+ UseOfInlineAssembly => crate::fluent_generated::mir_transform_use_of_asm_label,
+ InitializingTypeWith => {
+ crate::fluent_generated::mir_transform_initializing_valid_range_label
+ }
+ CastOfPointerToInt => crate::fluent_generated::mir_transform_const_ptr2int_label,
+ UseOfMutableStatic => crate::fluent_generated::mir_transform_use_of_static_mut_label,
+ UseOfExternStatic => crate::fluent_generated::mir_transform_use_of_extern_static_label,
+ DerefOfRawPointer => crate::fluent_generated::mir_transform_deref_ptr_label,
+ AccessToUnionField => crate::fluent_generated::mir_transform_union_access_label,
+ MutationOfLayoutConstrainedField => {
+ crate::fluent_generated::mir_transform_mutation_layout_constrained_label
+ }
+ BorrowOfLayoutConstrainedField => {
+ crate::fluent_generated::mir_transform_mutation_layout_constrained_borrow_label
+ }
+ CallToFunctionWith => crate::fluent_generated::mir_transform_target_feature_call_label,
+ }
+ }
+}
+
+pub(crate) struct UnsafeOpInUnsafeFn {
+ pub details: RequiresUnsafeDetail,
+}
+
+impl<'a> DecorateLint<'a, ()> for UnsafeOpInUnsafeFn {
+ #[track_caller]
+ fn decorate_lint<'b>(
+ self,
+ diag: &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()> {
+ let desc = diag
+ .handler()
+ .expect("lint should not yet be emitted")
+ .eagerly_translate_to_string(self.details.label(), [].into_iter());
+ diag.set_arg("details", desc);
+ diag.span_label(self.details.span, self.details.label());
+ diag.note(self.details.note());
+ diag
+ }
+
+ fn msg(&self) -> DiagnosticMessage {
+ crate::fluent_generated::mir_transform_unsafe_op_in_unsafe_fn
+ }
+}
+
+pub(crate) enum AssertLint<P> {
+ ArithmeticOverflow(Span, AssertKind<P>),
+ UnconditionalPanic(Span, AssertKind<P>),
+}
+
+impl<'a, P: std::fmt::Debug> DecorateLint<'a, ()> for AssertLint<P> {
+ fn decorate_lint<'b>(
+ self,
+ diag: &'b mut DiagnosticBuilder<'a, ()>,
+ ) -> &'b mut DiagnosticBuilder<'a, ()> {
+ diag.span_label(self.span(), format!("{:?}", self.panic()));
+ diag
+ }
+
+ fn msg(&self) -> DiagnosticMessage {
+ match self {
+ AssertLint::ArithmeticOverflow(..) => {
+ crate::fluent_generated::mir_transform_arithmetic_overflow
+ }
+ AssertLint::UnconditionalPanic(..) => {
+ crate::fluent_generated::mir_transform_operation_will_panic
+ }
+ }
+ }
+}
+
+impl<P> AssertLint<P> {
+ pub fn lint(&self) -> &'static Lint {
+ match self {
+ AssertLint::ArithmeticOverflow(..) => lint::builtin::ARITHMETIC_OVERFLOW,
+ AssertLint::UnconditionalPanic(..) => lint::builtin::UNCONDITIONAL_PANIC,
+ }
+ }
+ pub fn span(&self) -> Span {
+ match self {
+ AssertLint::ArithmeticOverflow(sp, _) | AssertLint::UnconditionalPanic(sp, _) => *sp,
+ }
+ }
+ pub fn panic(&self) -> &AssertKind<P> {
+ match self {
+ AssertLint::ArithmeticOverflow(_, p) | AssertLint::UnconditionalPanic(_, p) => p,
+ }
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_ffi_unwind_call)]
+pub(crate) struct FfiUnwindCall {
+ #[label(mir_transform_ffi_unwind_call)]
+ pub span: Span,
+ pub foreign: bool,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_fn_item_ref)]
+pub(crate) struct FnItemRef {
+ #[suggestion(code = "{sugg}", applicability = "unspecified")]
+ pub span: Span,
+ pub sugg: String,
+ pub ident: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(mir_transform_must_not_suspend)]
+pub(crate) struct MustNotSupend<'a> {
+ #[label]
+ pub yield_sp: Span,
+ #[subdiagnostic]
+ pub reason: Option<MustNotSuspendReason>,
+ #[help]
+ pub src_sp: Span,
+ pub pre: &'a str,
+ pub def_path: String,
+ pub post: &'a str,
+}
+
+#[derive(Subdiagnostic)]
+#[note(mir_transform_note)]
+pub(crate) struct MustNotSuspendReason {
+ #[primary_span]
+ pub span: Span,
+ pub reason: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(mir_transform_simd_shuffle_last_const)]
+pub(crate) struct SimdShuffleLastConst {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
index c9b24adba..58cc161dd 100644
--- a/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
+++ b/compiler/rustc_mir_transform/src/ffi_unwind_calls.rs
@@ -1,13 +1,15 @@
use rustc_hir::def_id::{LocalDefId, LOCAL_CRATE};
use rustc_middle::mir::*;
use rustc_middle::query::LocalCrate;
+use rustc_middle::query::Providers;
use rustc_middle::ty::layout;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::FFI_UNWIND_CALLS;
use rustc_target::spec::abi::Abi;
use rustc_target::spec::PanicStrategy;
+use crate::errors;
+
fn abi_can_unwind(abi: Abi) -> bool {
use Abi::*;
match abi {
@@ -48,7 +50,7 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
return false;
}
- let body = &*tcx.mir_built(ty::WithOptConstParam::unknown(local_def_id)).borrow();
+ let body = &*tcx.mir_built(local_def_id).borrow();
let body_ty = tcx.type_of(def_id).skip_binder();
let body_abi = match body_ty.kind() {
@@ -107,13 +109,13 @@ fn has_ffi_unwind_calls(tcx: TyCtxt<'_>, local_def_id: LocalDefId) -> bool {
.lint_root;
let span = terminator.source_info.span;
- let msg = match fn_def_id {
- Some(_) => "call to foreign function with FFI-unwind ABI",
- None => "call to function pointer with FFI-unwind ABI",
- };
- tcx.struct_span_lint_hir(FFI_UNWIND_CALLS, lint_root, span, msg, |lint| {
- lint.span_label(span, msg)
- });
+ let foreign = fn_def_id.is_some();
+ tcx.emit_spanned_lint(
+ FFI_UNWIND_CALLS,
+ lint_root,
+ span,
+ errors::FfiUnwindCall { span, foreign },
+ );
tainted = true;
}
diff --git a/compiler/rustc_mir_transform/src/function_item_references.rs b/compiler/rustc_mir_transform/src/function_item_references.rs
index 8601c1b2d..5989dbebf 100644
--- a/compiler/rustc_mir_transform/src/function_item_references.rs
+++ b/compiler/rustc_mir_transform/src/function_item_references.rs
@@ -1,14 +1,13 @@
use itertools::Itertools;
-use rustc_errors::Applicability;
use rustc_hir::def_id::DefId;
use rustc_middle::mir::visit::Visitor;
use rustc_middle::mir::*;
-use rustc_middle::ty::{self, EarlyBinder, GenericArgKind, PredicateKind, SubstsRef, Ty, TyCtxt};
+use rustc_middle::ty::{self, EarlyBinder, PredicateKind, SubstsRef, Ty, TyCtxt};
use rustc_session::lint::builtin::FUNCTION_ITEM_REFERENCES;
use rustc_span::{symbol::sym, Span};
use rustc_target::spec::abi::Abi;
-use crate::MirLint;
+use crate::{errors, MirLint};
pub struct FunctionItemReferences;
@@ -45,14 +44,12 @@ impl<'tcx> Visitor<'tcx> for FunctionItemRefChecker<'_, 'tcx> {
// Handle calls to `transmute`
if self.tcx.is_diagnostic_item(sym::transmute, def_id) {
let arg_ty = args[0].ty(self.body, self.tcx);
- for generic_inner_ty in arg_ty.walk() {
- if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
- if let Some((fn_id, fn_substs)) =
- FunctionItemRefChecker::is_fn_ref(inner_ty)
- {
- let span = self.nth_arg_span(&args, 0);
- self.emit_lint(fn_id, fn_substs, source_info, span);
- }
+ for inner_ty in arg_ty.walk().filter_map(|arg| arg.as_type()) {
+ if let Some((fn_id, fn_substs)) =
+ FunctionItemRefChecker::is_fn_ref(inner_ty)
+ {
+ let span = self.nth_arg_span(&args, 0);
+ self.emit_lint(fn_id, fn_substs, source_info, span);
}
}
} else {
@@ -82,24 +79,22 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
let arg_defs = self.tcx.fn_sig(def_id).subst_identity().skip_binder().inputs();
for (arg_num, arg_def) in arg_defs.iter().enumerate() {
// For all types reachable from the argument type in the fn sig
- for generic_inner_ty in arg_def.walk() {
- if let GenericArgKind::Type(inner_ty) = generic_inner_ty.unpack() {
- // If the inner type matches the type bound by `Pointer`
- if inner_ty == bound_ty {
- // Do a substitution using the parameters from the callsite
- let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref);
- if let Some((fn_id, fn_substs)) =
- FunctionItemRefChecker::is_fn_ref(subst_ty)
- {
- let mut span = self.nth_arg_span(args, arg_num);
- if span.from_expansion() {
- // The operand's ctxt wouldn't display the lint since it's inside a macro so
- // we have to use the callsite's ctxt.
- let callsite_ctxt = span.source_callsite().ctxt();
- span = span.with_ctxt(callsite_ctxt);
- }
- self.emit_lint(fn_id, fn_substs, source_info, span);
+ for inner_ty in arg_def.walk().filter_map(|arg| arg.as_type()) {
+ // If the inner type matches the type bound by `Pointer`
+ if inner_ty == bound_ty {
+ // Do a substitution using the parameters from the callsite
+ let subst_ty = EarlyBinder(inner_ty).subst(self.tcx, substs_ref);
+ if let Some((fn_id, fn_substs)) =
+ FunctionItemRefChecker::is_fn_ref(subst_ty)
+ {
+ let mut span = self.nth_arg_span(args, arg_num);
+ if span.from_expansion() {
+ // The operand's ctxt wouldn't display the lint since it's inside a macro so
+ // we have to use the callsite's ctxt.
+ let callsite_ctxt = span.source_callsite().ctxt();
+ span = span.with_ctxt(callsite_ctxt);
}
+ self.emit_lint(fn_id, fn_substs, source_info, span);
}
}
}
@@ -178,27 +173,21 @@ impl<'tcx> FunctionItemRefChecker<'_, 'tcx> {
let num_args = fn_sig.inputs().map_bound(|inputs| inputs.len()).skip_binder();
let variadic = if fn_sig.c_variadic() { ", ..." } else { "" };
let ret = if fn_sig.output().skip_binder().is_unit() { "" } else { " -> _" };
- self.tcx.struct_span_lint_hir(
+ let sugg = format!(
+ "{} as {}{}fn({}{}){}",
+ if params.is_empty() { ident.clone() } else { format!("{}::<{}>", ident, params) },
+ unsafety,
+ abi,
+ vec!["_"; num_args].join(", "),
+ variadic,
+ ret,
+ );
+
+ self.tcx.emit_spanned_lint(
FUNCTION_ITEM_REFERENCES,
lint_root,
span,
- "taking a reference to a function item does not give a function pointer",
- |lint| {
- lint.span_suggestion(
- span,
- format!("cast `{}` to obtain a function pointer", ident),
- format!(
- "{} as {}{}fn({}{}){}",
- if params.is_empty() { ident } else { format!("{}::<{}>", ident, params) },
- unsafety,
- abi,
- vec!["_"; num_args].join(", "),
- variadic,
- ret,
- ),
- Applicability::Unspecified,
- )
- },
+ errors::FnItemRef { span, sugg, ident },
);
}
}
diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs
index 4c4423721..89567ed0a 100644
--- a/compiler/rustc_mir_transform/src/generator.rs
+++ b/compiler/rustc_mir_transform/src/generator.rs
@@ -51,6 +51,7 @@
//! Otherwise it drops all the values in scope at the last suspension point.
use crate::deref_separator::deref_finder;
+use crate::errors;
use crate::simplify;
use crate::MirPass;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -59,7 +60,7 @@ use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
use rustc_hir::GeneratorKind;
use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_middle::mir::dump_mir;
use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor};
use rustc_middle::mir::*;
@@ -865,7 +866,7 @@ fn sanitize_witness<'tcx>(
_ => {
tcx.sess.delay_span_bug(
body.span,
- &format!("unexpected generator witness type {:?}", witness.kind()),
+ format!("unexpected generator witness type {:?}", witness.kind()),
);
return;
}
@@ -1044,7 +1045,10 @@ fn elaborate_generator_drops<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
for (block, block_data) in body.basic_blocks.iter_enumerated() {
let (target, unwind, source_info) = match block_data.terminator() {
- Terminator { source_info, kind: TerminatorKind::Drop { place, target, unwind } } => {
+ Terminator {
+ source_info,
+ kind: TerminatorKind::Drop { place, target, unwind, replace: _ },
+ } => {
if let Some(local) = place.as_local() {
if local == SELF_ARG {
(target, unwind, source_info)
@@ -1150,7 +1154,7 @@ fn insert_panic_block<'tcx>(
literal: ConstantKind::from_bool(tcx, false),
})),
expected: true,
- msg: message,
+ msg: Box::new(message),
target: assert_block,
unwind: UnwindAction::Continue,
};
@@ -1303,6 +1307,7 @@ fn insert_clean_drop(body: &mut Body<'_>) -> BasicBlock {
place: Place::from(SELF_ARG),
target: return_block,
unwind: UnwindAction::Continue,
+ replace: false,
};
let source_info = SourceInfo::outermost(body.span);
@@ -1396,10 +1401,10 @@ fn create_cases<'tcx>(
pub(crate) fn mir_generator_witnesses<'tcx>(
tcx: TyCtxt<'tcx>,
def_id: LocalDefId,
-) -> GeneratorLayout<'tcx> {
+) -> Option<GeneratorLayout<'tcx>> {
assert!(tcx.sess.opts.unstable_opts.drop_tracking_mir);
- let (body, _) = tcx.mir_promoted(ty::WithOptConstParam::unknown(def_id));
+ let (body, _) = tcx.mir_promoted(def_id);
let body = body.borrow();
let body = &*body;
@@ -1409,6 +1414,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
// Get the interior types and substs which typeck computed
let movable = match *gen_ty.kind() {
ty::Generator(_, _, movability) => movability == hir::Movability::Movable,
+ ty::Error(_) => return None,
_ => span_bug!(body.span, "unexpected generator type {}", gen_ty),
};
@@ -1424,7 +1430,7 @@ pub(crate) fn mir_generator_witnesses<'tcx>(
check_suspend_tys(tcx, &generator_layout, &body);
- generator_layout
+ Some(generator_layout)
}
impl<'tcx> MirPass<'tcx> for StateTransform {
@@ -1451,8 +1457,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform {
)
}
_ => {
- tcx.sess
- .delay_span_bug(body.span, &format!("unexpected generator type {}", gen_ty));
+ tcx.sess.delay_span_bug(body.span, format!("unexpected generator type {}", gen_ty));
return;
}
};
@@ -1800,7 +1805,7 @@ fn check_must_not_suspend_ty<'tcx>(
// FIXME: support adding the attribute to TAITs
ty::Alias(ty::Opaque, ty::AliasTy { def_id: def, .. }) => {
let mut has_emitted = false;
- for &(predicate, _) in tcx.explicit_item_bounds(def) {
+ for &(predicate, _) in tcx.explicit_item_bounds(def).skip_binder() {
// We only look at the `DefId`, so it is safe to skip the binder here.
if let ty::PredicateKind::Clause(ty::Clause::Trait(ref poly_trait_predicate)) =
predicate.kind().skip_binder()
@@ -1869,7 +1874,7 @@ fn check_must_not_suspend_ty<'tcx>(
},
)
}
- // If drop tracking is enabled, we want to look through references, since the referrent
+ // If drop tracking is enabled, we want to look through references, since the referent
// may not be considered live across the await point.
ty::Ref(_region, ty, _mutability) => {
let descr_pre = &format!("{}reference{} to ", data.descr_pre, plural_suffix);
@@ -1892,36 +1897,21 @@ fn check_must_not_suspend_def(
data: SuspendCheckData<'_>,
) -> bool {
if let Some(attr) = tcx.get_attr(def_id, sym::must_not_suspend) {
- let msg = rustc_errors::DelayDm(|| {
- format!(
- "{}`{}`{} held across a suspend point, but should not be",
- data.descr_pre,
- tcx.def_path_str(def_id),
- data.descr_post,
- )
+ let reason = attr.value_str().map(|s| errors::MustNotSuspendReason {
+ span: data.source_span,
+ reason: s.as_str().to_string(),
});
- tcx.struct_span_lint_hir(
+ tcx.emit_spanned_lint(
rustc_session::lint::builtin::MUST_NOT_SUSPEND,
hir_id,
data.source_span,
- msg,
- |lint| {
- // add span pointing to the offending yield/await
- lint.span_label(data.yield_span, "the value is held across this suspend point");
-
- // Add optional reason note
- if let Some(note) = attr.value_str() {
- // FIXME(guswynn): consider formatting this better
- lint.span_note(data.source_span, note.as_str());
- }
-
- // Add some quick suggestions on what to do
- // FIXME: can `drop` work as a suggestion here as well?
- lint.span_help(
- data.source_span,
- "consider using a block (`{ ... }`) \
- to shrink the value's scope, ending before the suspend point",
- )
+ errors::MustNotSupend {
+ yield_sp: data.yield_span,
+ reason,
+ src_sp: data.source_span,
+ pre: data.descr_pre,
+ def_path: tcx.def_path_str(def_id),
+ post: data.descr_post,
},
);
diff --git a/compiler/rustc_mir_transform/src/inline.rs b/compiler/rustc_mir_transform/src/inline.rs
index f0cb317f4..233de6dc6 100644
--- a/compiler/rustc_mir_transform/src/inline.rs
+++ b/compiler/rustc_mir_transform/src/inline.rs
@@ -3,13 +3,13 @@ use crate::deref_separator::deref_finder;
use rustc_attr::InlineAttr;
use rustc_hir::def_id::DefId;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
+use rustc_middle::ty::TypeVisitableExt;
use rustc_middle::ty::{self, Instance, InstanceDef, ParamEnv, Ty, TyCtxt};
use rustc_session::config::OptLevel;
-use rustc_span::{hygiene::ExpnKind, ExpnData, LocalExpnId, Span};
use rustc_target::abi::{FieldIdx, FIRST_VARIANT};
use rustc_target::spec::abi::Abi;
@@ -26,8 +26,6 @@ const CALL_PENALTY: usize = 25;
const LANDINGPAD_PENALTY: usize = 50;
const RESUME_PENALTY: usize = 45;
-const UNKNOWN_SIZE_COST: usize = 10;
-
const TOP_DOWN_DEPTH_LIMIT: usize = 5;
pub struct Inline;
@@ -169,8 +167,20 @@ impl<'tcx> Inliner<'tcx> {
) -> Result<std::ops::Range<BasicBlock>, &'static str> {
let callee_attrs = self.tcx.codegen_fn_attrs(callsite.callee.def_id());
self.check_codegen_attributes(callsite, callee_attrs)?;
+
+ let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
+ let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
+ let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
+ for arg in args {
+ if !arg.ty(&caller_body.local_decls, self.tcx).is_sized(self.tcx, self.param_env) {
+ // We do not allow inlining functions with unsized params. Inlining these functions
+ // could create unsized locals, which are unsound and being phased out.
+ return Err("Call has unsized argument");
+ }
+ }
+
self.check_mir_is_available(caller_body, &callsite.callee)?;
- let callee_body = self.tcx.instance_mir(callsite.callee.def);
+ let callee_body = try_instance_mir(self.tcx, callsite.callee.def)?;
self.check_mir_body(callsite, callee_body, callee_attrs)?;
if !self.tcx.consider_optimizing(|| {
@@ -182,7 +192,7 @@ impl<'tcx> Inliner<'tcx> {
let Ok(callee_body) = callsite.callee.try_subst_mir_and_normalize_erasing_regions(
self.tcx,
self.param_env,
- callee_body.clone(),
+ ty::EarlyBinder(callee_body.clone()),
) else {
return Err("failed to normalize callee body");
};
@@ -190,9 +200,6 @@ impl<'tcx> Inliner<'tcx> {
// Check call signature compatibility.
// Normally, this shouldn't be required, but trait normalization failure can create a
// validation ICE.
- let terminator = caller_body[callsite.block].terminator.as_ref().unwrap();
- let TerminatorKind::Call { args, destination, .. } = &terminator.kind else { bug!() };
- let destination_ty = destination.ty(&caller_body.local_decls, self.tcx).ty;
let output_type = callee_body.return_ty();
if !util::is_subtype(self.tcx, self.param_env, output_type, destination_ty) {
trace!(?output_type, ?destination_ty);
@@ -350,14 +357,8 @@ impl<'tcx> Inliner<'tcx> {
callsite: &CallSite<'tcx>,
callee_attrs: &CodegenFnAttrs,
) -> Result<(), &'static str> {
- match callee_attrs.inline {
- InlineAttr::Never => return Err("never inline hint"),
- InlineAttr::Always | InlineAttr::Hint => {}
- InlineAttr::None => {
- if self.tcx.sess.mir_opt_level() <= 2 {
- return Err("at mir-opt-level=2, only #[inline] is inlined");
- }
- }
+ if let InlineAttr::Never = callee_attrs.inline {
+ return Err("never inline hint");
}
// Only inline local functions if they would be eligible for cross-crate
@@ -436,6 +437,10 @@ impl<'tcx> Inliner<'tcx> {
validation: Ok(()),
};
+ for var_debug_info in callee_body.var_debug_info.iter() {
+ checker.visit_var_debug_info(var_debug_info);
+ }
+
// Traverse the MIR manually so we can account for the effects of inlining on the CFG.
let mut work_list = vec![START_BLOCK];
let mut visited = BitSet::new_empty(callee_body.basic_blocks.len());
@@ -448,14 +453,16 @@ impl<'tcx> Inliner<'tcx> {
checker.visit_basic_block_data(bb, blk);
let term = blk.terminator();
- if let TerminatorKind::Drop { ref place, target, unwind } = term.kind {
+ if let TerminatorKind::Drop { ref place, target, unwind, replace: _ } = term.kind {
work_list.push(target);
// If the place doesn't actually need dropping, treat it like a regular goto.
- let ty = callsite.callee.subst_mir(self.tcx, &place.ty(callee_body, tcx).ty);
+ let ty = callsite
+ .callee
+ .subst_mir(self.tcx, ty::EarlyBinder(&place.ty(callee_body, tcx).ty));
if ty.needs_drop(tcx, self.param_env) && let UnwindAction::Cleanup(unwind) = unwind {
- work_list.push(unwind);
- }
+ work_list.push(unwind);
+ }
} else if callee_attrs.instruction_set != self.codegen_fn_attrs.instruction_set
&& matches!(term.kind, TerminatorKind::InlineAsm { .. })
{
@@ -470,12 +477,6 @@ impl<'tcx> Inliner<'tcx> {
}
}
- // Count up the cost of local variables and temps, if we know the size
- // use that, otherwise we use a moderately-large dummy cost.
- for v in callee_body.vars_and_temps_iter() {
- checker.visit_local_decl(v, &callee_body.local_decls[v]);
- }
-
// Abort if type validation found anything fishy.
checker.validation?;
@@ -553,16 +554,6 @@ impl<'tcx> Inliner<'tcx> {
// Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, &callee_body);
- let mut expn_data = ExpnData::default(
- ExpnKind::Inlined,
- callsite.source_info.span,
- self.tcx.sess.edition(),
- None,
- None,
- );
- expn_data.def_site = callee_body.span;
- let expn_data =
- self.tcx.with_stable_hashing_context(|hcx| LocalExpnId::fresh(expn_data, hcx));
let mut integrator = Integrator {
args: &args,
new_locals: Local::new(caller_body.local_decls.len())..,
@@ -574,7 +565,6 @@ impl<'tcx> Inliner<'tcx> {
cleanup_block: unwind,
in_cleanup_block: false,
tcx: self.tcx,
- expn_data,
always_live_locals: BitSet::new_filled(callee_body.local_decls.len()),
};
@@ -770,14 +760,6 @@ impl<'tcx> Inliner<'tcx> {
}
}
-fn type_size_of<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>,
-) -> Option<u64> {
- tcx.layout_of(param_env.and(ty)).ok().map(|layout| layout.size.bytes())
-}
-
/// Verify that the callee body is compatible with the caller.
///
/// This visitor mostly computes the inlining cost,
@@ -810,7 +792,9 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
match terminator.kind {
TerminatorKind::Drop { ref place, unwind, .. } => {
// If the place doesn't actually need dropping, treat it like a regular goto.
- let ty = self.instance.subst_mir(tcx, &place.ty(self.callee_body, tcx).ty);
+ let ty = self
+ .instance
+ .subst_mir(tcx, ty::EarlyBinder(&place.ty(self.callee_body, tcx).ty));
if ty.needs_drop(tcx, self.param_env) {
self.cost += CALL_PENALTY;
if let UnwindAction::Cleanup(_) = unwind {
@@ -821,7 +805,7 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
}
}
TerminatorKind::Call { func: Operand::Constant(ref f), unwind, .. } => {
- let fn_ty = self.instance.subst_mir(tcx, &f.literal.ty());
+ let fn_ty = self.instance.subst_mir(tcx, ty::EarlyBinder(&f.literal.ty()));
self.cost += if let ty::FnDef(def_id, _) = *fn_ty.kind() && tcx.is_intrinsic(def_id) {
// Don't give intrinsics the extra penalty for calls
INSTR_COST
@@ -851,24 +835,6 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
self.super_terminator(terminator, location);
}
- /// Count up the cost of local variables and temps, if we know the size
- /// use that, otherwise we use a moderately-large dummy cost.
- fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) {
- let tcx = self.tcx;
- let ptr_size = tcx.data_layout.pointer_size.bytes();
-
- let ty = self.instance.subst_mir(tcx, &local_decl.ty);
- // Cost of the var is the size in machine-words, if we know
- // it.
- if let Some(size) = type_size_of(tcx, self.param_env, ty) {
- self.cost += ((size + ptr_size - 1) / ptr_size) as usize;
- } else {
- self.cost += UNKNOWN_SIZE_COST;
- }
-
- self.super_local_decl(local, local_decl)
- }
-
/// This method duplicates code from MIR validation in an attempt to detect type mismatches due
/// to normalization failure.
fn visit_projection_elem(
@@ -883,7 +849,16 @@ impl<'tcx> Visitor<'tcx> for CostChecker<'_, 'tcx> {
let parent = Place { local, projection: self.tcx.mk_place_elems(proj_base) };
let parent_ty = parent.ty(&self.callee_body.local_decls, self.tcx);
let check_equal = |this: &mut Self, f_ty| {
- if !util::is_equal_up_to_subtyping(this.tcx, this.param_env, ty, f_ty) {
+ // Fast path if there is nothing to substitute.
+ if ty == f_ty {
+ return;
+ }
+ let ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder(&ty));
+ let f_ty = this.instance.subst_mir(this.tcx, ty::EarlyBinder(&f_ty));
+ if ty == f_ty {
+ return;
+ }
+ if !util::is_subtype(this.tcx, this.param_env, ty, f_ty) {
trace!(?ty, ?f_ty);
this.validation = Err("failed to normalize projection type");
return;
@@ -982,7 +957,6 @@ struct Integrator<'a, 'tcx> {
cleanup_block: UnwindAction,
in_cleanup_block: bool,
tcx: TyCtxt<'tcx>,
- expn_data: LocalExpnId,
always_live_locals: BitSet<Local>,
}
@@ -1068,11 +1042,6 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
*scope = self.map_scope(*scope);
}
- fn visit_span(&mut self, span: &mut Span) {
- // Make sure that all spans track the fact that they were inlined.
- *span = span.fresh_expansion(self.expn_data);
- }
-
fn visit_basic_block_data(&mut self, block: BasicBlock, data: &mut BasicBlockData<'tcx>) {
self.in_cleanup_block = data.is_cleanup;
self.super_basic_block_data(block, data);
@@ -1164,3 +1133,27 @@ impl<'tcx> MutVisitor<'tcx> for Integrator<'_, 'tcx> {
}
}
}
+
+#[instrument(skip(tcx), level = "debug")]
+fn try_instance_mir<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: InstanceDef<'tcx>,
+) -> Result<&'tcx Body<'tcx>, &'static str> {
+ match instance {
+ ty::InstanceDef::DropGlue(_, Some(ty)) => match ty.kind() {
+ ty::Adt(def, substs) => {
+ let fields = def.all_fields();
+ for field in fields {
+ let field_ty = field.ty(tcx, substs);
+ if field_ty.has_param() && field_ty.has_projections() {
+ return Err("cannot build drop shim for polymorphic type");
+ }
+ }
+
+ Ok(tcx.instance_mir(instance))
+ }
+ _ => Ok(tcx.instance_mir(instance)),
+ },
+ _ => Ok(tcx.instance_mir(instance)),
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/inline/cycle.rs b/compiler/rustc_mir_transform/src/inline/cycle.rs
index 8aa3c23d0..1ccf06f61 100644
--- a/compiler/rustc_mir_transform/src/inline/cycle.rs
+++ b/compiler/rustc_mir_transform/src/inline/cycle.rs
@@ -13,7 +13,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
tcx: TyCtxt<'tcx>,
(root, target): (ty::Instance<'tcx>, LocalDefId),
) -> bool {
- trace!(%root, target = %tcx.def_path_str(target.to_def_id()));
+ trace!(%root, target = %tcx.def_path_str(target));
let param_env = tcx.param_env_reveal_all_normalized(target);
assert_ne!(
root.def_id().expect_local(),
@@ -44,7 +44,11 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
) -> bool {
trace!(%caller);
for &(callee, substs) in tcx.mir_inliner_callees(caller.def) {
- let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(tcx, param_env, substs) else {
+ let Ok(substs) = caller.try_subst_mir_and_normalize_erasing_regions(
+ tcx,
+ param_env,
+ ty::EarlyBinder(substs),
+ ) else {
trace!(?caller, ?param_env, ?substs, "cannot normalize, skipping");
continue;
};
@@ -92,7 +96,7 @@ pub(crate) fn mir_callgraph_reachable<'tcx>(
// FIXME: A not fully substituted drop shim can cause ICEs if one attempts to
// have its MIR built. Likely oli-obk just screwed up the `ParamEnv`s, so this
// needs some more analysis.
- if callee.needs_subst() {
+ if callee.has_param() {
continue;
}
}
@@ -148,8 +152,7 @@ pub(crate) fn mir_inliner_callees<'tcx>(
let guard;
let body = match (instance, instance.def_id().as_local()) {
(InstanceDef::Item(_), Some(def_id)) => {
- let def = ty::WithOptConstParam::unknown(def_id);
- steal = tcx.mir_promoted(def).0;
+ steal = tcx.mir_promoted(def_id).0;
guard = steal.borrow();
&*guard
}
diff --git a/compiler/rustc_mir_transform/src/instcombine.rs b/compiler/rustc_mir_transform/src/instsimplify.rs
index 3d06a0a49..e4dc61762 100644
--- a/compiler/rustc_mir_transform/src/instcombine.rs
+++ b/compiler/rustc_mir_transform/src/instsimplify.rs
@@ -1,26 +1,23 @@
//! Performs various peephole optimizations.
+use crate::simplify::simplify_duplicate_switch_targets;
use crate::MirPass;
use rustc_hir::Mutability;
-use rustc_middle::mir::{
- BinOp, Body, CastKind, Constant, ConstantKind, LocalDecls, Operand, Place, ProjectionElem,
- Rvalue, SourceInfo, Statement, StatementKind, SwitchTargets, Terminator, TerminatorKind, UnOp,
-};
+use rustc_middle::mir::*;
use rustc_middle::ty::layout::ValidityRequirement;
-use rustc_middle::ty::util::IntTypeExt;
use rustc_middle::ty::{self, ParamEnv, SubstsRef, Ty, TyCtxt};
use rustc_span::symbol::Symbol;
use rustc_target::abi::FieldIdx;
-pub struct InstCombine;
+pub struct InstSimplify;
-impl<'tcx> MirPass<'tcx> for InstCombine {
+impl<'tcx> MirPass<'tcx> for InstSimplify {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
sess.mir_opt_level() > 0
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let ctx = InstCombineContext {
+ let ctx = InstSimplifyContext {
tcx,
local_decls: &body.local_decls,
param_env: tcx.param_env_reveal_all_normalized(body.source.def_id()),
@@ -29,43 +26,43 @@ impl<'tcx> MirPass<'tcx> for InstCombine {
for statement in block.statements.iter_mut() {
match statement.kind {
StatementKind::Assign(box (_place, ref mut rvalue)) => {
- ctx.combine_bool_cmp(&statement.source_info, rvalue);
- ctx.combine_ref_deref(&statement.source_info, rvalue);
- ctx.combine_len(&statement.source_info, rvalue);
- ctx.combine_cast(&statement.source_info, rvalue);
+ ctx.simplify_bool_cmp(&statement.source_info, rvalue);
+ ctx.simplify_ref_deref(&statement.source_info, rvalue);
+ ctx.simplify_len(&statement.source_info, rvalue);
+ ctx.simplify_cast(&statement.source_info, rvalue);
}
_ => {}
}
}
- ctx.combine_primitive_clone(
+ ctx.simplify_primitive_clone(
&mut block.terminator.as_mut().unwrap(),
&mut block.statements,
);
- ctx.combine_intrinsic_assert(
+ ctx.simplify_intrinsic_assert(
&mut block.terminator.as_mut().unwrap(),
&mut block.statements,
);
- ctx.combine_duplicate_switch_targets(&mut block.terminator.as_mut().unwrap());
+ simplify_duplicate_switch_targets(block.terminator.as_mut().unwrap());
}
}
}
-struct InstCombineContext<'tcx, 'a> {
+struct InstSimplifyContext<'tcx, 'a> {
tcx: TyCtxt<'tcx>,
local_decls: &'a LocalDecls<'tcx>,
param_env: ParamEnv<'tcx>,
}
-impl<'tcx> InstCombineContext<'tcx, '_> {
- fn should_combine(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
+impl<'tcx> InstSimplifyContext<'tcx, '_> {
+ fn should_simplify(&self, source_info: &SourceInfo, rvalue: &Rvalue<'tcx>) -> bool {
self.tcx.consider_optimizing(|| {
- format!("InstCombine - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
+ format!("InstSimplify - Rvalue: {:?} SourceInfo: {:?}", rvalue, source_info)
})
}
/// Transform boolean comparisons into logical operations.
- fn combine_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ fn simplify_bool_cmp(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
match rvalue {
Rvalue::BinaryOp(op @ (BinOp::Eq | BinOp::Ne), box (a, b)) => {
let new = match (op, self.try_eval_bool(a), self.try_eval_bool(b)) {
@@ -96,7 +93,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
_ => None,
};
- if let Some(new) = new && self.should_combine(source_info, rvalue) {
+ if let Some(new) = new && self.should_simplify(source_info, rvalue) {
*rvalue = new;
}
}
@@ -111,14 +108,14 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
}
/// Transform "&(*a)" ==> "a".
- fn combine_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ fn simplify_ref_deref(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Ref(_, _, place) = rvalue {
if let Some((base, ProjectionElem::Deref)) = place.as_ref().last_projection() {
if rvalue.ty(self.local_decls, self.tcx) != base.ty(self.local_decls, self.tcx).ty {
return;
}
- if !self.should_combine(source_info, rvalue) {
+ if !self.should_simplify(source_info, rvalue) {
return;
}
@@ -131,11 +128,11 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
}
/// Transform "Len([_; N])" ==> "N".
- fn combine_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ fn simplify_len(&self, source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Len(ref place) = *rvalue {
let place_ty = place.ty(self.local_decls, self.tcx).ty;
if let ty::Array(_, len) = *place_ty.kind() {
- if !self.should_combine(source_info, rvalue) {
+ if !self.should_simplify(source_info, rvalue) {
return;
}
@@ -146,7 +143,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
}
}
- fn combine_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
+ fn simplify_cast(&self, _source_info: &SourceInfo, rvalue: &mut Rvalue<'tcx>) {
if let Rvalue::Cast(kind, operand, cast_ty) = rvalue {
let operand_ty = operand.ty(self.local_decls, self.tcx);
if operand_ty == *cast_ty {
@@ -165,18 +162,6 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
return;
}
- // Transmuting a fieldless enum to its repr is a discriminant read
- if let ty::Adt(adt_def, ..) = operand_ty.kind()
- && adt_def.is_enum()
- && adt_def.is_payloadfree()
- && let Some(place) = operand.place()
- && let Some(repr_int) = adt_def.repr().int
- && repr_int.to_ty(self.tcx) == *cast_ty
- {
- *rvalue = Rvalue::Discriminant(place);
- return;
- }
-
// Transmuting a transparent struct/union to a field's type is a projection
if let ty::Adt(adt_def, substs) = operand_ty.kind()
&& adt_def.repr().transparent()
@@ -198,7 +183,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
}
}
- fn combine_primitive_clone(
+ fn simplify_primitive_clone(
&self,
terminator: &mut Terminator<'tcx>,
statements: &mut Vec<Statement<'tcx>>,
@@ -241,7 +226,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
if !self.tcx.consider_optimizing(|| {
format!(
- "InstCombine - Call: {:?} SourceInfo: {:?}",
+ "InstSimplify - Call: {:?} SourceInfo: {:?}",
(fn_def_id, fn_substs),
terminator.source_info
)
@@ -264,20 +249,7 @@ impl<'tcx> InstCombineContext<'tcx, '_> {
terminator.kind = TerminatorKind::Goto { target: destination_block };
}
- fn combine_duplicate_switch_targets(&self, terminator: &mut Terminator<'tcx>) {
- let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind
- else { return };
-
- let otherwise = targets.otherwise();
- if targets.iter().any(|t| t.1 == otherwise) {
- *targets = SwitchTargets::new(
- targets.iter().filter(|t| t.1 != otherwise),
- targets.otherwise(),
- );
- }
- }
-
- fn combine_intrinsic_assert(
+ fn simplify_intrinsic_assert(
&self,
terminator: &mut Terminator<'tcx>,
_statements: &mut Vec<Statement<'tcx>>,
diff --git a/compiler/rustc_mir_transform/src/large_enums.rs b/compiler/rustc_mir_transform/src/large_enums.rs
index 9447a2ff0..430a6f6ce 100644
--- a/compiler/rustc_mir_transform/src/large_enums.rs
+++ b/compiler/rustc_mir_transform/src/large_enums.rs
@@ -120,7 +120,7 @@ impl EnumSizeOpt {
fn optim<'tcx>(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let mut alloc_cache = FxHashMap::default();
let body_did = body.source.def_id();
- let param_env = tcx.param_env(body_did);
+ let param_env = tcx.param_env_reveal_all_normalized(body_did);
let blocks = body.basic_blocks.as_mut();
let local_decls = &mut body.local_decls;
diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs
index fc12d423c..65864dc01 100644
--- a/compiler/rustc_mir_transform/src/lib.rs
+++ b/compiler/rustc_mir_transform/src/lib.rs
@@ -1,4 +1,6 @@
#![allow(rustc::potential_query_instability)]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
#![feature(box_patterns)]
#![feature(drain_filter)]
#![feature(let_chains)]
@@ -23,18 +25,19 @@ use rustc_data_structures::fx::FxIndexSet;
use rustc_data_structures::steal::Steal;
use rustc_hir as hir;
use rustc_hir::def::DefKind;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::visit::Visitor as _;
use rustc_middle::mir::{
traversal, AnalysisPhase, Body, ClearCrossCrate, ConstQualifs, Constant, LocalDecl, MirPass,
MirPhase, Operand, Place, ProjectionElem, Promoted, RuntimePhase, Rvalue, SourceInfo,
- Statement, StatementKind, TerminatorKind,
+ Statement, StatementKind, TerminatorKind, START_BLOCK,
};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeVisitableExt};
use rustc_span::sym;
+use rustc_trait_selection::traits;
#[macro_use]
mod pass_manager;
@@ -48,6 +51,7 @@ mod add_retag;
mod check_const_item_mutation;
mod check_packed_ref;
pub mod check_unsafety;
+mod remove_place_mention;
// This pass is public to allow external drivers to perform MIR cleanup
pub mod cleanup_post_borrowck;
mod const_debuginfo;
@@ -67,11 +71,12 @@ pub mod dump_mir;
mod early_otherwise_branch;
mod elaborate_box_derefs;
mod elaborate_drops;
+mod errors;
mod ffi_unwind_calls;
mod function_item_references;
mod generator;
mod inline;
-mod instcombine;
+mod instsimplify;
mod large_enums;
mod lower_intrinsics;
mod lower_slice_len;
@@ -79,6 +84,7 @@ mod match_branches;
mod multiple_return_terminators;
mod normalize_array_len;
mod nrvo;
+mod ref_prop;
mod remove_noop_landing_pads;
mod remove_storage_markers;
mod remove_uninit_drops;
@@ -103,6 +109,11 @@ use rustc_const_eval::transform::promote_consts;
use rustc_const_eval::transform::validate;
use rustc_mir_dataflow::rustc_peek;
+use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
+
+fluent_messages! { "../messages.ftl" }
+
pub fn provide(providers: &mut Providers) {
check_unsafety::provide(providers);
coverage::query::provide(providers);
@@ -111,36 +122,17 @@ pub fn provide(providers: &mut Providers) {
*providers = Providers {
mir_keys,
mir_const,
- mir_const_qualif: |tcx, def_id| {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.mir_const_qualif_const_arg(def)
- } else {
- mir_const_qualif(tcx, ty::WithOptConstParam::unknown(def_id))
- }
- },
- mir_const_qualif_const_arg: |tcx, (did, param_did)| {
- mir_const_qualif(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
- },
+ mir_const_qualif,
mir_promoted,
mir_drops_elaborated_and_const_checked,
mir_for_ctfe,
- mir_for_ctfe_of_const_arg,
mir_generator_witnesses: generator::mir_generator_witnesses,
optimized_mir,
is_mir_available,
is_ctfe_mir_available: |tcx, did| is_mir_available(tcx, did),
mir_callgraph_reachable: inline::cycle::mir_callgraph_reachable,
mir_inliner_callees: inline::cycle::mir_inliner_callees,
- promoted_mir: |tcx, def_id| {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.promoted_mir_of_const_arg(def)
- } else {
- promoted_mir(tcx, ty::WithOptConstParam::unknown(def_id))
- }
- },
- promoted_mir_of_const_arg: |tcx, (did, param_did)| {
- promoted_mir(tcx, ty::WithOptConstParam { did, const_param_did: Some(param_did) })
- },
+ promoted_mir,
deduced_param_attrs: deduce_param_attrs::deduced_param_attrs,
..*providers
};
@@ -234,8 +226,8 @@ fn mir_keys(tcx: TyCtxt<'_>, (): ()) -> FxIndexSet<LocalDefId> {
set
}
-fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> ConstQualifs {
- let const_kind = tcx.hir().body_const_context(def.did);
+fn mir_const_qualif(tcx: TyCtxt<'_>, def: LocalDefId) -> ConstQualifs {
+ let const_kind = tcx.hir().body_const_context(def);
// No need to const-check a non-const `fn`.
if const_kind.is_none() {
@@ -253,7 +245,7 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) ->
return Default::default();
}
- let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def.did) };
+ let ccx = check_consts::ConstCx { body, tcx, const_kind, param_env: tcx.param_env(def) };
let mut validator = check_consts::check::Checker::new(&ccx);
validator.check_body();
@@ -266,22 +258,14 @@ fn mir_const_qualif(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) ->
/// Make MIR ready for const evaluation. This is run on all MIR, not just on consts!
/// FIXME(oli-obk): it's unclear whether we still need this phase (and its corresponding query).
/// We used to have this for pre-miri MIR based const eval.
-fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<Body<'_>> {
- if let Some(def) = def.try_upgrade(tcx) {
- return tcx.mir_const(def);
- }
-
+fn mir_const(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
// Unsafety check uses the raw mir, so make sure it is run.
if !tcx.sess.opts.unstable_opts.thir_unsafeck {
- if let Some(param_did) = def.const_param_did {
- tcx.ensure_with_value().unsafety_check_result_for_const_arg((def.did, param_did));
- } else {
- tcx.ensure_with_value().unsafety_check_result(def.did);
- }
+ tcx.ensure_with_value().unsafety_check_result(def);
}
// has_ffi_unwind_calls query uses the raw mir, so make sure it is run.
- tcx.ensure_with_value().has_ffi_unwind_calls(def.did);
+ tcx.ensure_with_value().has_ffi_unwind_calls(def);
let mut body = tcx.mir_built(def).steal();
@@ -296,7 +280,7 @@ fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<
&Lint(check_const_item_mutation::CheckConstItemMutation),
&Lint(function_item_references::FunctionItemReferences),
// What we need to do constant evaluation.
- &simplify::SimplifyCfg::new("initial"),
+ &simplify::SimplifyCfg::Initial,
&rustc_peek::SanityCheck, // Just a lint
],
None,
@@ -307,16 +291,12 @@ fn mir_const(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> &Steal<
/// Compute the main MIR body and the list of MIR bodies of the promoteds.
fn mir_promoted(
tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
+ def: LocalDefId,
) -> (&Steal<Body<'_>>, &Steal<IndexVec<Promoted, Body<'_>>>) {
- if let Some(def) = def.try_upgrade(tcx) {
- return tcx.mir_promoted(def);
- }
-
// Ensure that we compute the `mir_const_qualif` for constants at
// this point, before we steal the mir-const result.
// Also this means promotion can rely on all const checks having been done.
- let const_qualifs = tcx.mir_const_qualif_opt_const_arg(def);
+ let const_qualifs = tcx.mir_const_qualif(def);
let mut body = tcx.mir_const(def).steal();
if let Some(error_reported) = const_qualifs.tainted_by_errors {
body.tainted_by_errors = Some(error_reported);
@@ -334,11 +314,7 @@ fn mir_promoted(
pm::run_passes(
tcx,
&mut body,
- &[
- &promote_pass,
- &simplify::SimplifyCfg::new("promote-consts"),
- &coverage::InstrumentCoverage,
- ],
+ &[&promote_pass, &simplify::SimplifyCfg::PromoteConsts, &coverage::InstrumentCoverage],
Some(MirPhase::Analysis(AnalysisPhase::Initial)),
);
@@ -348,38 +324,22 @@ fn mir_promoted(
/// Compute the MIR that is used during CTFE (and thus has no optimizations run on it)
fn mir_for_ctfe(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &Body<'_> {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.mir_for_ctfe_of_const_arg(def)
- } else {
- tcx.arena.alloc(inner_mir_for_ctfe(tcx, ty::WithOptConstParam::unknown(def_id)))
- }
+ tcx.arena.alloc(inner_mir_for_ctfe(tcx, def_id))
}
-/// Same as `mir_for_ctfe`, but used to get the MIR of a const generic parameter.
-/// The docs on `WithOptConstParam` explain this a bit more, but the TLDR is that
-/// we'd get cycle errors with `mir_for_ctfe`, because typeck would need to typeck
-/// the const parameter while type checking the main body, which in turn would try
-/// to type check the main body again.
-fn mir_for_ctfe_of_const_arg(tcx: TyCtxt<'_>, (did, param_did): (LocalDefId, DefId)) -> &Body<'_> {
- tcx.arena.alloc(inner_mir_for_ctfe(
- tcx,
- ty::WithOptConstParam { did, const_param_did: Some(param_did) },
- ))
-}
-
-fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -> Body<'_> {
+fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> {
// FIXME: don't duplicate this between the optimized_mir/mir_for_ctfe queries
- if tcx.is_constructor(def.did.to_def_id()) {
+ if tcx.is_constructor(def.to_def_id()) {
// There's no reason to run all of the MIR passes on constructors when
// we can just output the MIR we want directly. This also saves const
// qualification and borrow checking the trouble of special casing
// constructors.
- return shim::build_adt_ctor(tcx, def.did.to_def_id());
+ return shim::build_adt_ctor(tcx, def.to_def_id());
}
let context = tcx
.hir()
- .body_const_context(def.did)
+ .body_const_context(def)
.expect("mir_for_ctfe should not be used for runtime functions");
let body = tcx.mir_drops_elaborated_and_const_checked(def).borrow().clone();
@@ -417,29 +377,19 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: ty::WithOptConstParam<LocalDefId>) -
/// Obtain just the main MIR (no promoteds) and run some cleanups on it. This also runs
/// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't
/// end up missing the source MIR due to stealing happening.
-fn mir_drops_elaborated_and_const_checked(
- tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> &Steal<Body<'_>> {
- if let Some(def) = def.try_upgrade(tcx) {
- return tcx.mir_drops_elaborated_and_const_checked(def);
- }
-
+fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal<Body<'_>> {
if tcx.sess.opts.unstable_opts.drop_tracking_mir
- && let DefKind::Generator = tcx.def_kind(def.did)
+ && let DefKind::Generator = tcx.def_kind(def)
{
- tcx.ensure_with_value().mir_generator_witnesses(def.did);
+ tcx.ensure_with_value().mir_generator_witnesses(def);
}
- let mir_borrowck = tcx.mir_borrowck_opt_const_arg(def);
+ let mir_borrowck = tcx.mir_borrowck(def);
- let is_fn_like = tcx.def_kind(def.did).is_fn_like();
+ let is_fn_like = tcx.def_kind(def).is_fn_like();
if is_fn_like {
- let did = def.did.to_def_id();
- let def = ty::WithOptConstParam::unknown(did);
-
// Do not compute the mir call graph without said call graph actually being used.
if inline::Inline.is_enabled(&tcx.sess) {
- tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def));
+ tcx.ensure_with_value().mir_inliner_callees(ty::InstanceDef::Item(def.to_def_id()));
}
}
@@ -449,6 +399,50 @@ fn mir_drops_elaborated_and_const_checked(
body.tainted_by_errors = Some(error_reported);
}
+ // Check if it's even possible to satisfy the 'where' clauses
+ // for this item.
+ //
+ // This branch will never be taken for any normal function.
+ // However, it's possible to `#!feature(trivial_bounds)]` to write
+ // a function with impossible to satisfy clauses, e.g.:
+ // `fn foo() where String: Copy {}`
+ //
+ // We don't usually need to worry about this kind of case,
+ // since we would get a compilation error if the user tried
+ // to call it. However, since we optimize even without any
+ // calls to the function, we need to make sure that it even
+ // makes sense to try to evaluate the body.
+ //
+ // If there are unsatisfiable where clauses, then all bets are
+ // off, and we just give up.
+ //
+ // We manually filter the predicates, skipping anything that's not
+ // "global". We are in a potentially generic context
+ // (e.g. we are evaluating a function without substituting generic
+ // parameters, so this filtering serves two purposes:
+ //
+ // 1. We skip evaluating any predicates that we would
+ // never be able prove are unsatisfiable (e.g. `<T as Foo>`
+ // 2. We avoid trying to normalize predicates involving generic
+ // parameters (e.g. `<T as Foo>::MyItem`). This can confuse
+ // the normalization code (leading to cycle errors), since
+ // it's usually never invoked in this way.
+ let predicates = tcx
+ .predicates_of(body.source.def_id())
+ .predicates
+ .iter()
+ .filter_map(|(p, _)| if p.is_global() { Some(*p) } else { None });
+ if traits::impossible_predicates(tcx, traits::elaborate(tcx, predicates).collect()) {
+ trace!("found unsatisfiable predicates for {:?}", body.source);
+ // Clear the body to only contain a single `unreachable` statement.
+ let bbs = body.basic_blocks.as_mut();
+ bbs.raw.truncate(1);
+ bbs[START_BLOCK].statements.clear();
+ bbs[START_BLOCK].terminator_mut().kind = TerminatorKind::Unreachable;
+ body.var_debug_info.clear();
+ body.local_decls.raw.truncate(body.arg_count + 1);
+ }
+
run_analysis_to_runtime_passes(tcx, &mut body);
tcx.alloc_steal_mir(body)
@@ -467,10 +461,7 @@ fn run_analysis_to_runtime_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>
pm::run_passes(
tcx,
body,
- &[
- &remove_uninit_drops::RemoveUninitDrops,
- &simplify::SimplifyCfg::new("remove-false-edges"),
- ],
+ &[&remove_uninit_drops::RemoveUninitDrops, &simplify::SimplifyCfg::RemoveFalseEdges],
None,
);
check_consts::post_drop_elaboration::check_live_drops(tcx, &body); // FIXME: make this a MIR lint
@@ -492,7 +483,7 @@ fn run_analysis_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let passes: &[&dyn MirPass<'tcx>] = &[
&cleanup_post_borrowck::CleanupPostBorrowck,
&remove_noop_landing_pads::RemoveNoopLandingPads,
- &simplify::SimplifyCfg::new("early-opt"),
+ &simplify::SimplifyCfg::EarlyOpt,
&deref_separator::Derefer,
];
@@ -524,8 +515,11 @@ fn run_runtime_lowering_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
/// Returns the sequence of passes that do the initial cleanup of runtime MIR.
fn run_runtime_cleanup_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let passes: &[&dyn MirPass<'tcx>] =
- &[&lower_intrinsics::LowerIntrinsics, &simplify::SimplifyCfg::new("elaborate-drops")];
+ let passes: &[&dyn MirPass<'tcx>] = &[
+ &lower_intrinsics::LowerIntrinsics,
+ &remove_place_mention::RemovePlaceMention,
+ &simplify::SimplifyCfg::ElaborateDrops,
+ ];
pm::run_passes(tcx, body, passes, Some(MirPhase::Runtime(RuntimePhase::PostCleanup)));
@@ -551,7 +545,7 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&lower_slice_len::LowerSliceLenCalls, // has to be done before inlining, otherwise actual call will be almost always inlined. Also simple, so can just do first
&unreachable_prop::UnreachablePropagation,
&uninhabited_enum_branching::UninhabitedEnumBranching,
- &o1(simplify::SimplifyCfg::new("after-uninhabited-enum-branching")),
+ &o1(simplify::SimplifyCfg::AfterUninhabitedEnumBranching),
&inline::Inline,
&remove_storage_markers::RemoveStorageMarkers,
&remove_zsts::RemoveZsts,
@@ -562,25 +556,26 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
&match_branches::MatchBranchSimplification,
// inst combine is after MatchBranchSimplification to clean up Ne(_1, false)
&multiple_return_terminators::MultipleReturnTerminators,
- &instcombine::InstCombine,
+ &instsimplify::InstSimplify,
&separate_const_switch::SeparateConstSwitch,
- &simplify::SimplifyLocals::new("before-const-prop"),
+ &simplify::SimplifyLocals::BeforeConstProp,
&copy_prop::CopyProp,
+ &ref_prop::ReferencePropagation,
&const_prop::ConstProp,
&dataflow_const_prop::DataflowConstProp,
//
// Const-prop runs unconditionally, but doesn't mutate the MIR at mir-opt-level=0.
&const_debuginfo::ConstDebugInfo,
- &o1(simplify_branches::SimplifyConstCondition::new("after-const-prop")),
+ &o1(simplify_branches::SimplifyConstCondition::AfterConstProp),
&early_otherwise_branch::EarlyOtherwiseBranch,
&simplify_comparison_integral::SimplifyComparisonIntegral,
&dead_store_elimination::DeadStoreElimination,
&dest_prop::DestinationPropagation,
- &o1(simplify_branches::SimplifyConstCondition::new("final")),
+ &o1(simplify_branches::SimplifyConstCondition::Final),
&o1(remove_noop_landing_pads::RemoveNoopLandingPads),
- &o1(simplify::SimplifyCfg::new("final")),
+ &o1(simplify::SimplifyCfg::Final),
&nrvo::RenameReturnPlace,
- &simplify::SimplifyLocals::new("final"),
+ &simplify::SimplifyLocals::Final,
&multiple_return_terminators::MultipleReturnTerminators,
&deduplicate_blocks::DeduplicateBlocks,
&large_enums::EnumSizeOpt { discrepancy: 128 },
@@ -595,7 +590,6 @@ fn run_optimization_passes<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
/// Optimize the MIR and prepare it for codegen.
fn optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> &Body<'_> {
- assert_eq!(ty::WithOptConstParam::try_lookup(did, tcx), None);
tcx.arena.alloc(inner_optimized_mir(tcx, did))
}
@@ -617,8 +611,7 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
Some(other) => panic!("do not use `optimized_mir` for constants: {:?}", other),
}
debug!("about to call mir_drops_elaborated...");
- let body =
- tcx.mir_drops_elaborated_and_const_checked(ty::WithOptConstParam::unknown(did)).steal();
+ let body = tcx.mir_drops_elaborated_and_const_checked(did).steal();
let mut body = remap_mir_for_const_eval_select(tcx, body, hir::Constness::NotConst);
debug!("body: {:#?}", body);
run_optimization_passes(tcx, &mut body);
@@ -628,21 +621,15 @@ fn inner_optimized_mir(tcx: TyCtxt<'_>, did: LocalDefId) -> Body<'_> {
/// Fetch all the promoteds of an item and prepare their MIR bodies to be ready for
/// constant evaluation once all substitutions become known.
-fn promoted_mir(
- tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> &IndexVec<Promoted, Body<'_>> {
- if tcx.is_constructor(def.did.to_def_id()) {
+fn promoted_mir(tcx: TyCtxt<'_>, def: LocalDefId) -> &IndexVec<Promoted, Body<'_>> {
+ if tcx.is_constructor(def.to_def_id()) {
return tcx.arena.alloc(IndexVec::new());
}
- let tainted_by_errors = tcx.mir_borrowck_opt_const_arg(def).tainted_by_errors;
+ tcx.ensure_with_value().mir_borrowck(def);
let mut promoted = tcx.mir_promoted(def).1.steal();
for body in &mut promoted {
- if let Some(error_reported) = tainted_by_errors {
- body.tainted_by_errors = Some(error_reported);
- }
run_analysis_to_runtime_passes(tcx, body);
}
diff --git a/compiler/rustc_mir_transform/src/lower_intrinsics.rs b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
index c136642df..dae01e41e 100644
--- a/compiler/rustc_mir_transform/src/lower_intrinsics.rs
+++ b/compiler/rustc_mir_transform/src/lower_intrinsics.rs
@@ -1,6 +1,6 @@
//! Lowers intrinsic calls
-use crate::MirPass;
+use crate::{errors, MirPass};
use rustc_middle::mir::*;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Ty, TyCtxt};
@@ -179,6 +179,29 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
}
}
}
+ sym::write_via_move => {
+ let target = target.unwrap();
+ let Ok([ptr, val]) = <[_; 2]>::try_from(std::mem::take(args)) else {
+ span_bug!(
+ terminator.source_info.span,
+ "Wrong number of arguments for write_via_move intrinsic",
+ );
+ };
+ let derefed_place =
+ if let Some(place) = ptr.place() && let Some(local) = place.as_local() {
+ tcx.mk_place_deref(local.into())
+ } else {
+ span_bug!(terminator.source_info.span, "Only passing a local is supported");
+ };
+ block.statements.push(Statement {
+ source_info: terminator.source_info,
+ kind: StatementKind::Assign(Box::new((
+ derefed_place,
+ Rvalue::Use(val),
+ ))),
+ });
+ terminator.kind = TerminatorKind::Goto { target };
+ }
sym::discriminant_value => {
if let (Some(target), Some(arg)) = (*target, args[0].place()) {
let arg = tcx.mk_place_deref(arg);
@@ -192,6 +215,23 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Goto { target };
}
}
+ sym::offset => {
+ let target = target.unwrap();
+ let Ok([ptr, delta]) = <[_; 2]>::try_from(std::mem::take(args)) else {
+ span_bug!(
+ terminator.source_info.span,
+ "Wrong number of arguments for offset intrinsic",
+ );
+ };
+ block.statements.push(Statement {
+ source_info: terminator.source_info,
+ kind: StatementKind::Assign(Box::new((
+ *destination,
+ Rvalue::BinaryOp(BinOp::Offset, Box::new((ptr, delta))),
+ ))),
+ });
+ terminator.kind = TerminatorKind::Goto { target };
+ }
sym::option_payload_ptr => {
if let (Some(target), Some(arg)) = (*target, args[0].place()) {
let ty::RawPtr(ty::TypeAndMut { ty: dest_ty, .. }) =
@@ -221,7 +261,7 @@ impl<'tcx> MirPass<'tcx> for LowerIntrinsics {
terminator.kind = TerminatorKind::Goto { target };
}
}
- sym::transmute => {
+ sym::transmute | sym::transmute_unchecked => {
let dst_ty = destination.ty(local_decls, tcx).ty;
let Ok([arg]) = <[_; 1]>::try_from(std::mem::take(args)) else {
span_bug!(
@@ -270,11 +310,7 @@ fn resolve_rust_intrinsic<'tcx>(
}
fn validate_simd_shuffle<'tcx>(tcx: TyCtxt<'tcx>, args: &[Operand<'tcx>], span: Span) {
- match &args[2] {
- Operand::Constant(_) => {} // all good
- _ => {
- let msg = "last argument of `simd_shuffle` is required to be a `const` item";
- tcx.sess.span_err(span, msg);
- }
+ if !matches!(args[2], Operand::Constant(_)) {
+ tcx.sess.emit_err(errors::SimdShuffleLastConst { span });
}
}
diff --git a/compiler/rustc_mir_transform/src/lower_slice_len.rs b/compiler/rustc_mir_transform/src/lower_slice_len.rs
index 7dc5878e0..6e40dfa0d 100644
--- a/compiler/rustc_mir_transform/src/lower_slice_len.rs
+++ b/compiler/rustc_mir_transform/src/lower_slice_len.rs
@@ -3,7 +3,7 @@
use crate::MirPass;
use rustc_hir::def_id::DefId;
-use rustc_index::vec::IndexSlice;
+use rustc_index::IndexSlice;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
diff --git a/compiler/rustc_mir_transform/src/match_branches.rs b/compiler/rustc_mir_transform/src/match_branches.rs
index ce05db5b7..59942dc76 100644
--- a/compiler/rustc_mir_transform/src/match_branches.rs
+++ b/compiler/rustc_mir_transform/src/match_branches.rs
@@ -46,7 +46,7 @@ impl<'tcx> MirPass<'tcx> for MatchBranchSimplification {
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
let def_id = body.source.def_id();
- let param_env = tcx.param_env(def_id);
+ let param_env = tcx.param_env_reveal_all_normalized(def_id);
let bbs = body.basic_blocks.as_mut();
let mut should_cleanup = false;
diff --git a/compiler/rustc_mir_transform/src/normalize_array_len.rs b/compiler/rustc_mir_transform/src/normalize_array_len.rs
index b36c8a0bd..3d61d33ce 100644
--- a/compiler/rustc_mir_transform/src/normalize_array_len.rs
+++ b/compiler/rustc_mir_transform/src/normalize_array_len.rs
@@ -3,11 +3,10 @@
use crate::ssa::SsaLocals;
use crate::MirPass;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
use rustc_middle::ty::{self, TyCtxt};
-use rustc_mir_dataflow::impls::borrowed_locals;
pub struct NormalizeArrayLen;
@@ -24,9 +23,7 @@ impl<'tcx> MirPass<'tcx> for NormalizeArrayLen {
}
fn normalize_array_len_calls<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
- let borrowed_locals = borrowed_locals(body);
- let ssa = SsaLocals::new(tcx, param_env, body, &borrowed_locals);
+ let ssa = SsaLocals::new(body);
let slice_lengths = compute_slice_length(tcx, &ssa, body);
debug!(?slice_lengths);
@@ -41,7 +38,7 @@ fn compute_slice_length<'tcx>(
) -> IndexVec<Local, Option<ty::Const<'tcx>>> {
let mut slice_lengths = IndexVec::from_elem(None, &body.local_decls);
- for (local, rvalue) in ssa.assignments(body) {
+ for (local, rvalue, _) in ssa.assignments(body) {
match rvalue {
Rvalue::Cast(
CastKind::Pointer(ty::adjustment::PointerCast::Unsize),
diff --git a/compiler/rustc_mir_transform/src/nrvo.rs b/compiler/rustc_mir_transform/src/nrvo.rs
index b6e73eaad..5ce96012b 100644
--- a/compiler/rustc_mir_transform/src/nrvo.rs
+++ b/compiler/rustc_mir_transform/src/nrvo.rs
@@ -34,7 +34,8 @@ pub struct RenameReturnPlace;
impl<'tcx> MirPass<'tcx> for RenameReturnPlace {
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
- sess.mir_opt_level() > 0
+ // #111005
+ sess.mir_opt_level() > 0 && sess.opts.unstable_opts.unsound_mir_opts
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut mir::Body<'tcx>) {
@@ -107,7 +108,7 @@ fn local_eligible_for_nrvo(body: &mut mir::Body<'_>) -> Option<Local> {
// If multiple different locals are copied to the return place. We can't pick a
// single one to rename.
- if copied_to_return_place.map_or(false, |old| old != returned_local) {
+ if copied_to_return_place.is_some_and(|old| old != returned_local) {
return None;
}
diff --git a/compiler/rustc_mir_transform/src/pass_manager.rs b/compiler/rustc_mir_transform/src/pass_manager.rs
index e1b65823a..710eed3ed 100644
--- a/compiler/rustc_mir_transform/src/pass_manager.rs
+++ b/compiler/rustc_mir_transform/src/pass_manager.rs
@@ -6,7 +6,7 @@ use crate::{validate, MirPass};
/// Just like `MirPass`, except it cannot mutate `Body`.
pub trait MirLint<'tcx> {
- fn name(&self) -> &str {
+ fn name(&self) -> &'static str {
let name = std::any::type_name::<Self>();
if let Some((_, tail)) = name.rsplit_once(':') { tail } else { name }
}
@@ -26,7 +26,7 @@ impl<'tcx, T> MirPass<'tcx> for Lint<T>
where
T: MirLint<'tcx>,
{
- fn name(&self) -> &str {
+ fn name(&self) -> &'static str {
self.0.name()
}
@@ -49,7 +49,7 @@ impl<'tcx, T> MirPass<'tcx> for WithMinOptLevel<T>
where
T: MirPass<'tcx>,
{
- fn name(&self) -> &str {
+ fn name(&self) -> &'static str {
self.1.name()
}
@@ -121,7 +121,7 @@ fn run_passes_inner<'tcx>(
validate_body(tcx, body, format!("before pass {}", name));
}
- pass.run_pass(tcx, body);
+ tcx.sess.time(name, || pass.run_pass(tcx, body));
if dump_enabled {
dump_mir_for_pass(tcx, body, &name, true);
diff --git a/compiler/rustc_mir_transform/src/ref_prop.rs b/compiler/rustc_mir_transform/src/ref_prop.rs
new file mode 100644
index 000000000..bbd9f76ba
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/ref_prop.rs
@@ -0,0 +1,408 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_index::bit_set::BitSet;
+use rustc_index::IndexVec;
+use rustc_middle::mir::visit::*;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+use rustc_mir_dataflow::impls::MaybeStorageDead;
+use rustc_mir_dataflow::storage::always_storage_live_locals;
+use rustc_mir_dataflow::Analysis;
+
+use crate::ssa::{SsaLocals, StorageLiveLocals};
+use crate::MirPass;
+
+/// Propagate references using SSA analysis.
+///
+/// MIR building may produce a lot of borrow-dereference patterns.
+///
+/// This pass aims to transform the following pattern:
+/// _1 = &raw? mut? PLACE;
+/// _3 = *_1;
+/// _4 = &raw? mut? *_1;
+///
+/// Into
+/// _1 = &raw? mut? PLACE;
+/// _3 = PLACE;
+/// _4 = &raw? mut? PLACE;
+///
+/// where `PLACE` is a direct or an indirect place expression.
+///
+/// There are 3 properties that need to be upheld for this transformation to be legal:
+/// - place stability: `PLACE` must refer to the same memory wherever it appears;
+/// - pointer liveness: we must not introduce dereferences of dangling pointers;
+/// - `&mut` borrow uniqueness.
+///
+/// # Stability
+///
+/// If `PLACE` is an indirect projection, if its of the form `(*LOCAL).PROJECTIONS` where:
+/// - `LOCAL` is SSA;
+/// - all projections in `PROJECTIONS` have a stable offset (no dereference and no indexing).
+///
+/// If `PLACE` is a direct projection of a local, we consider it as constant if:
+/// - the local is always live, or it has a single `StorageLive`;
+/// - all projections have a stable offset.
+///
+/// # Liveness
+///
+/// When performing a substitution, we must take care not to introduce uses of dangling locals.
+/// To ensure this, we walk the body with the `MaybeStorageDead` dataflow analysis:
+/// - if we want to replace `*x` by reborrow `*y` and `y` may be dead, we allow replacement and
+/// mark storage statements on `y` for removal;
+/// - if we want to replace `*x` by non-reborrow `y` and `y` must be live, we allow replacement;
+/// - if we want to replace `*x` by non-reborrow `y` and `y` may be dead, we do not replace.
+///
+/// # Uniqueness
+///
+/// For `&mut` borrows, we also need to preserve the uniqueness property:
+/// we must avoid creating a state where we interleave uses of `*_1` and `_2`.
+/// To do it, we only perform full substitution of mutable borrows:
+/// we replace either all or none of the occurrences of `*_1`.
+///
+/// Some care has to be taken when `_1` is copied in other locals.
+/// _1 = &raw? mut? _2;
+/// _3 = *_1;
+/// _4 = _1
+/// _5 = *_4
+/// In such cases, fully substituting `_1` means fully substituting all of the copies.
+///
+/// For immutable borrows, we do not need to preserve such uniqueness property,
+/// so we perform all the possible substitutions without removing the `_1 = &_2` statement.
+pub struct ReferencePropagation;
+
+impl<'tcx> MirPass<'tcx> for ReferencePropagation {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ sess.mir_opt_level() >= 4
+ }
+
+ #[instrument(level = "trace", skip(self, tcx, body))]
+ fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ debug!(def_id = ?body.source.def_id());
+ while propagate_ssa(tcx, body) {}
+ }
+}
+
+fn propagate_ssa<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) -> bool {
+ let ssa = SsaLocals::new(body);
+
+ let mut replacer = compute_replacement(tcx, body, &ssa);
+ debug!(?replacer.targets);
+ debug!(?replacer.allowed_replacements);
+ debug!(?replacer.storage_to_remove);
+
+ replacer.visit_body_preserves_cfg(body);
+
+ if replacer.any_replacement {
+ crate::simplify::remove_unused_definitions(body);
+ }
+
+ replacer.any_replacement
+}
+
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum Value<'tcx> {
+ /// Not a pointer, or we can't know.
+ Unknown,
+ /// We know the value to be a pointer to this place.
+ /// The boolean indicates whether the reference is mutable, subject the uniqueness rule.
+ Pointer(Place<'tcx>, bool),
+}
+
+/// For each local, save the place corresponding to `*local`.
+#[instrument(level = "trace", skip(tcx, body))]
+fn compute_replacement<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ body: &Body<'tcx>,
+ ssa: &SsaLocals,
+) -> Replacer<'tcx> {
+ let always_live_locals = always_storage_live_locals(body);
+
+ // Compute which locals have a single `StorageLive` statement ever.
+ let storage_live = StorageLiveLocals::new(body, &always_live_locals);
+
+ // Compute `MaybeStorageDead` dataflow to check that we only replace when the pointee is
+ // definitely live.
+ let mut maybe_dead = MaybeStorageDead::new(always_live_locals)
+ .into_engine(tcx, body)
+ .iterate_to_fixpoint()
+ .into_results_cursor(body);
+
+ // Map for each local to the pointee.
+ let mut targets = IndexVec::from_elem(Value::Unknown, &body.local_decls);
+ // Set of locals for which we will remove their storage statement. This is useful for
+ // reborrowed references.
+ let mut storage_to_remove = BitSet::new_empty(body.local_decls.len());
+
+ let fully_replacable_locals = fully_replacable_locals(ssa);
+
+ // Returns true iff we can use `place` as a pointee.
+ //
+ // Note that we only need to verify that there is a single `StorageLive` statement, and we do
+ // not need to verify that it dominates all uses of that local.
+ //
+ // Consider the three statements:
+ // SL : StorageLive(a)
+ // DEF: b = &raw? mut? a
+ // USE: stuff that uses *b
+ //
+ // First, we recall that DEF is checked to dominate USE. Now imagine for the sake of
+ // contradiction there is a DEF -> SL -> USE path. Consider two cases:
+ //
+ // - DEF dominates SL. We always have UB the first time control flow reaches DEF,
+ // because the storage of `a` is dead. Since DEF dominates USE, that means we cannot
+ // reach USE and so our optimization is ok.
+ //
+ // - DEF does not dominate SL. Then there is a `START_BLOCK -> SL` path not including DEF.
+ // But we can extend this path to USE, meaning there is also a `START_BLOCK -> USE` path not
+ // including DEF. This violates the DEF dominates USE condition, and so is impossible.
+ let is_constant_place = |place: Place<'_>| {
+ // We only allow `Deref` as the first projection, to avoid surprises.
+ if place.projection.first() == Some(&PlaceElem::Deref) {
+ // `place == (*some_local).xxx`, it is constant only if `some_local` is constant.
+ // We approximate constness using SSAness.
+ ssa.is_ssa(place.local) && place.projection[1..].iter().all(PlaceElem::is_stable_offset)
+ } else {
+ storage_live.has_single_storage(place.local)
+ && place.projection[..].iter().all(PlaceElem::is_stable_offset)
+ }
+ };
+
+ let mut can_perform_opt = |target: Place<'tcx>, loc: Location| {
+ if target.projection.first() == Some(&PlaceElem::Deref) {
+ // We are creating a reborrow. As `place.local` is a reference, removing the storage
+ // statements should not make it much harder for LLVM to optimize.
+ storage_to_remove.insert(target.local);
+ true
+ } else {
+ // This is a proper dereference. We can only allow it if `target` is live.
+ maybe_dead.seek_after_primary_effect(loc);
+ let maybe_dead = maybe_dead.contains(target.local);
+ !maybe_dead
+ }
+ };
+
+ for (local, rvalue, location) in ssa.assignments(body) {
+ debug!(?local);
+
+ // Only visit if we have something to do.
+ let Value::Unknown = targets[local] else { bug!() };
+
+ let ty = body.local_decls[local].ty;
+
+ // If this is not a reference or pointer, do nothing.
+ if !ty.is_any_ptr() {
+ debug!("not a reference or pointer");
+ continue;
+ }
+
+ // Whether the current local is subject to the uniqueness rule.
+ let needs_unique = ty.is_mutable_ptr();
+
+ // If this a mutable reference that we cannot fully replace, mark it as unknown.
+ if needs_unique && !fully_replacable_locals.contains(local) {
+ debug!("not fully replaceable");
+ continue;
+ }
+
+ debug!(?rvalue);
+ match rvalue {
+ // This is a copy, just use the value we have in store for the previous one.
+ // As we are visiting in `assignment_order`, ie. reverse postorder, `rhs` should
+ // have been visited before.
+ Rvalue::Use(Operand::Copy(place) | Operand::Move(place))
+ | Rvalue::CopyForDeref(place) => {
+ if let Some(rhs) = place.as_local() && ssa.is_ssa(rhs) {
+ let target = targets[rhs];
+ // Only see through immutable reference and pointers, as we do not know yet if
+ // mutable references are fully replaced.
+ if !needs_unique && matches!(target, Value::Pointer(..)) {
+ targets[local] = target;
+ } else {
+ targets[local] = Value::Pointer(tcx.mk_place_deref(rhs.into()), needs_unique);
+ }
+ }
+ }
+ Rvalue::Ref(_, _, place) | Rvalue::AddressOf(_, place) => {
+ let mut place = *place;
+ // Try to see through `place` in order to collapse reborrow chains.
+ if place.projection.first() == Some(&PlaceElem::Deref)
+ && let Value::Pointer(target, inner_needs_unique) = targets[place.local]
+ // Only see through immutable reference and pointers, as we do not know yet if
+ // mutable references are fully replaced.
+ && !inner_needs_unique
+ // Only collapse chain if the pointee is definitely live.
+ && can_perform_opt(target, location)
+ {
+ place = target.project_deeper(&place.projection[1..], tcx);
+ }
+ assert_ne!(place.local, local);
+ if is_constant_place(place) {
+ targets[local] = Value::Pointer(place, needs_unique);
+ }
+ }
+ // We do not know what to do, so keep as not-a-pointer.
+ _ => {}
+ }
+ }
+
+ debug!(?targets);
+
+ let mut finder = ReplacementFinder {
+ targets: &mut targets,
+ can_perform_opt,
+ allowed_replacements: FxHashSet::default(),
+ };
+ let reachable_blocks = traversal::reachable_as_bitset(body);
+ for (bb, bbdata) in body.basic_blocks.iter_enumerated() {
+ // Only visit reachable blocks as we rely on dataflow.
+ if reachable_blocks.contains(bb) {
+ finder.visit_basic_block_data(bb, bbdata);
+ }
+ }
+
+ let allowed_replacements = finder.allowed_replacements;
+ return Replacer {
+ tcx,
+ targets,
+ storage_to_remove,
+ allowed_replacements,
+ fully_replacable_locals,
+ any_replacement: false,
+ };
+
+ struct ReplacementFinder<'a, 'tcx, F> {
+ targets: &'a mut IndexVec<Local, Value<'tcx>>,
+ can_perform_opt: F,
+ allowed_replacements: FxHashSet<(Local, Location)>,
+ }
+
+ impl<'tcx, F> Visitor<'tcx> for ReplacementFinder<'_, 'tcx, F>
+ where
+ F: FnMut(Place<'tcx>, Location) -> bool,
+ {
+ fn visit_place(&mut self, place: &Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+ if matches!(ctxt, PlaceContext::NonUse(_)) {
+ // There is no need to check liveness for non-uses.
+ return;
+ }
+
+ if place.projection.first() != Some(&PlaceElem::Deref) {
+ // This is not a dereference, nothing to do.
+ return;
+ }
+
+ let mut place = place.as_ref();
+ loop {
+ if let Value::Pointer(target, needs_unique) = self.targets[place.local] {
+ let perform_opt = (self.can_perform_opt)(target, loc);
+ debug!(?place, ?target, ?needs_unique, ?perform_opt);
+
+ // This a reborrow chain, recursively allow the replacement.
+ //
+ // This also allows to detect cases where `target.local` is not replacable,
+ // and mark it as such.
+ if let &[PlaceElem::Deref] = &target.projection[..] {
+ assert!(perform_opt);
+ self.allowed_replacements.insert((target.local, loc));
+ place.local = target.local;
+ continue;
+ } else if perform_opt {
+ self.allowed_replacements.insert((target.local, loc));
+ } else if needs_unique {
+ // This mutable reference is not fully replacable, so drop it.
+ self.targets[place.local] = Value::Unknown;
+ }
+ }
+
+ break;
+ }
+ }
+ }
+}
+
+/// Compute the set of locals that can be fully replaced.
+///
+/// We consider a local to be replacable iff it's only used in a `Deref` projection `*_local` or
+/// non-use position (like storage statements and debuginfo).
+fn fully_replacable_locals(ssa: &SsaLocals) -> BitSet<Local> {
+ let mut replacable = BitSet::new_empty(ssa.num_locals());
+
+ // First pass: for each local, whether its uses can be fully replaced.
+ for local in ssa.locals() {
+ if ssa.num_direct_uses(local) == 0 {
+ replacable.insert(local);
+ }
+ }
+
+ // Second pass: a local can only be fully replaced if all its copies can.
+ ssa.meet_copy_equivalence(&mut replacable);
+
+ replacable
+}
+
+/// Utility to help performing subtitution of `*pattern` by `target`.
+struct Replacer<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ targets: IndexVec<Local, Value<'tcx>>,
+ storage_to_remove: BitSet<Local>,
+ allowed_replacements: FxHashSet<(Local, Location)>,
+ any_replacement: bool,
+ fully_replacable_locals: BitSet<Local>,
+}
+
+impl<'tcx> MutVisitor<'tcx> for Replacer<'tcx> {
+ fn tcx(&self) -> TyCtxt<'tcx> {
+ self.tcx
+ }
+
+ fn visit_var_debug_info(&mut self, debuginfo: &mut VarDebugInfo<'tcx>) {
+ if let VarDebugInfoContents::Place(ref mut place) = debuginfo.value
+ && place.projection.is_empty()
+ && let Value::Pointer(target, _) = self.targets[place.local]
+ && target.projection.iter().all(|p| p.can_use_in_debuginfo())
+ {
+ if let Some((&PlaceElem::Deref, rest)) = target.projection.split_last() {
+ *place = Place::from(target.local).project_deeper(rest, self.tcx);
+ self.any_replacement = true;
+ } else if self.fully_replacable_locals.contains(place.local)
+ && let Some(references) = debuginfo.references.checked_add(1)
+ {
+ debuginfo.references = references;
+ *place = target;
+ self.any_replacement = true;
+ }
+ }
+ }
+
+ fn visit_place(&mut self, place: &mut Place<'tcx>, ctxt: PlaceContext, loc: Location) {
+ if place.projection.first() != Some(&PlaceElem::Deref) {
+ return;
+ }
+
+ loop {
+ if let Value::Pointer(target, _) = self.targets[place.local] {
+ let perform_opt = matches!(ctxt, PlaceContext::NonUse(_))
+ || self.allowed_replacements.contains(&(target.local, loc));
+
+ if perform_opt {
+ *place = target.project_deeper(&place.projection[1..], self.tcx);
+ self.any_replacement = true;
+ continue;
+ }
+ }
+
+ break;
+ }
+ }
+
+ fn visit_statement(&mut self, stmt: &mut Statement<'tcx>, loc: Location) {
+ match stmt.kind {
+ StatementKind::StorageLive(l) | StatementKind::StorageDead(l)
+ if self.storage_to_remove.contains(l) =>
+ {
+ stmt.make_nop();
+ }
+ // Do not remove assignments as they may still be useful for debuginfo.
+ _ => self.super_statement(stmt, loc),
+ }
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/remove_place_mention.rs b/compiler/rustc_mir_transform/src/remove_place_mention.rs
new file mode 100644
index 000000000..8be1c3757
--- /dev/null
+++ b/compiler/rustc_mir_transform/src/remove_place_mention.rs
@@ -0,0 +1,23 @@
+//! This pass removes `PlaceMention` statement, which has no effect at codegen.
+
+use crate::MirPass;
+use rustc_middle::mir::*;
+use rustc_middle::ty::TyCtxt;
+
+pub struct RemovePlaceMention;
+
+impl<'tcx> MirPass<'tcx> for RemovePlaceMention {
+ fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
+ !sess.opts.unstable_opts.mir_keep_place_mention
+ }
+
+ fn run_pass(&self, _: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
+ trace!("Running RemovePlaceMention on {:?}", body.source);
+ for data in body.basic_blocks.as_mut_preserves_cfg() {
+ data.statements.retain(|statement| match statement.kind {
+ StatementKind::PlaceMention(..) | StatementKind::Nop => false,
+ _ => true,
+ })
+ }
+ }
+}
diff --git a/compiler/rustc_mir_transform/src/reveal_all.rs b/compiler/rustc_mir_transform/src/reveal_all.rs
index abe6cb285..23442f8b9 100644
--- a/compiler/rustc_mir_transform/src/reveal_all.rs
+++ b/compiler/rustc_mir_transform/src/reveal_all.rs
@@ -35,10 +35,22 @@ impl<'tcx> MutVisitor<'tcx> for RevealAllVisitor<'tcx> {
}
#[inline]
+ fn visit_constant(&mut self, constant: &mut Constant<'tcx>, _: Location) {
+ // We have to use `try_normalize_erasing_regions` here, since it's
+ // possible that we visit impossible-to-satisfy where clauses here,
+ // see #91745
+ if let Ok(c) = self.tcx.try_normalize_erasing_regions(self.param_env, constant.literal) {
+ constant.literal = c;
+ }
+ }
+
+ #[inline]
fn visit_ty(&mut self, ty: &mut Ty<'tcx>, _: TyContext) {
// We have to use `try_normalize_erasing_regions` here, since it's
// possible that we visit impossible-to-satisfy where clauses here,
// see #91745
- *ty = self.tcx.try_normalize_erasing_regions(self.param_env, *ty).unwrap_or(*ty);
+ if let Ok(t) = self.tcx.try_normalize_erasing_regions(self.param_env, *ty) {
+ *ty = t;
+ }
}
}
diff --git a/compiler/rustc_mir_transform/src/separate_const_switch.rs b/compiler/rustc_mir_transform/src/separate_const_switch.rs
index ef367faf6..2479856b7 100644
--- a/compiler/rustc_mir_transform/src/separate_const_switch.rs
+++ b/compiler/rustc_mir_transform/src/separate_const_switch.rs
@@ -303,8 +303,7 @@ fn find_determining_place<'tcx>(
| Rvalue::NullaryOp(_, _)
| Rvalue::ShallowInitBox(_, _)
| Rvalue::UnaryOp(_, Operand::Constant(_))
- | Rvalue::Cast(_, Operand::Constant(_), _)
- => return None,
+ | Rvalue::Cast(_, Operand::Constant(_), _) => return None,
}
}
diff --git a/compiler/rustc_mir_transform/src/shim.rs b/compiler/rustc_mir_transform/src/shim.rs
index 2787fe2ce..0eb27c231 100644
--- a/compiler/rustc_mir_transform/src/shim.rs
+++ b/compiler/rustc_mir_transform/src/shim.rs
@@ -2,12 +2,12 @@ use rustc_hir as hir;
use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::*;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, EarlyBinder, GeneratorSubsts, Ty, TyCtxt};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_span::Span;
use rustc_target::spec::abi::Abi;
@@ -95,7 +95,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
&add_moves_for_packed_drops::AddMovesForPackedDrops,
&deref_separator::Derefer,
&remove_noop_landing_pads::RemoveNoopLandingPads,
- &simplify::SimplifyCfg::new("make_shim"),
+ &simplify::SimplifyCfg::MakeShim,
&add_call_guards::CriticalCallEdges,
&abort_unwinding_calls::AbortUnwindingCalls,
],
@@ -355,7 +355,7 @@ fn build_thread_local_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'t
fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) -> Body<'tcx> {
debug!("build_clone_shim(def_id={:?})", def_id);
- let param_env = tcx.param_env(def_id);
+ let param_env = tcx.param_env_reveal_all_normalized(def_id);
let mut builder = CloneShimBuilder::new(tcx, def_id, self_ty);
let is_copy = self_ty.is_copy_modulo_regions(tcx, param_env);
@@ -544,6 +544,7 @@ impl<'tcx> CloneShimBuilder<'tcx> {
place: dest_field,
target: unwind,
unwind: UnwindAction::Terminate,
+ replace: false,
},
true,
);
@@ -800,6 +801,7 @@ fn build_call_shim<'tcx>(
place: rcvr_place(),
target: BasicBlock::new(2),
unwind: UnwindAction::Continue,
+ replace: false,
},
false,
);
@@ -815,6 +817,7 @@ fn build_call_shim<'tcx>(
place: rcvr_place(),
target: BasicBlock::new(4),
unwind: UnwindAction::Terminate,
+ replace: false,
},
true,
);
@@ -836,7 +839,7 @@ fn build_call_shim<'tcx>(
pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> {
debug_assert!(tcx.is_constructor(ctor_id));
- let param_env = tcx.param_env(ctor_id);
+ let param_env = tcx.param_env_reveal_all_normalized(ctor_id);
// Normalize the sig.
let sig = tcx
diff --git a/compiler/rustc_mir_transform/src/simplify.rs b/compiler/rustc_mir_transform/src/simplify.rs
index c79e1cf08..e59219321 100644
--- a/compiler/rustc_mir_transform/src/simplify.rs
+++ b/compiler/rustc_mir_transform/src/simplify.rs
@@ -29,20 +29,38 @@
use crate::MirPass;
use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
-use rustc_index::vec::{Idx, IndexSlice, IndexVec};
+use rustc_index::{Idx, IndexSlice, IndexVec};
use rustc_middle::mir::coverage::*;
use rustc_middle::mir::visit::{MutVisitor, MutatingUseContext, PlaceContext, Visitor};
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
use smallvec::SmallVec;
-pub struct SimplifyCfg {
- label: String,
+pub enum SimplifyCfg {
+ Initial,
+ PromoteConsts,
+ RemoveFalseEdges,
+ EarlyOpt,
+ ElaborateDrops,
+ Final,
+ MakeShim,
+ AfterUninhabitedEnumBranching,
}
impl SimplifyCfg {
- pub fn new(label: &str) -> Self {
- SimplifyCfg { label: format!("SimplifyCfg-{}", label) }
+ pub fn name(&self) -> &'static str {
+ match self {
+ SimplifyCfg::Initial => "SimplifyCfg-initial",
+ SimplifyCfg::PromoteConsts => "SimplifyCfg-promote-consts",
+ SimplifyCfg::RemoveFalseEdges => "SimplifyCfg-remove-false-edges",
+ SimplifyCfg::EarlyOpt => "SimplifyCfg-early-opt",
+ SimplifyCfg::ElaborateDrops => "SimplifyCfg-elaborate-drops",
+ SimplifyCfg::Final => "SimplifyCfg-final",
+ SimplifyCfg::MakeShim => "SimplifyCfg-make_shim",
+ SimplifyCfg::AfterUninhabitedEnumBranching => {
+ "SimplifyCfg-after-uninhabited-enum-branching"
+ }
+ }
}
}
@@ -56,12 +74,12 @@ pub fn simplify_cfg<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
}
impl<'tcx> MirPass<'tcx> for SimplifyCfg {
- fn name(&self) -> &str {
- &self.label
+ fn name(&self) -> &'static str {
+ &self.name()
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- debug!("SimplifyCfg({:?}) - simplifying {:?}", self.label, body.source);
+ debug!("SimplifyCfg({:?}) - simplifying {:?}", self.name(), body.source);
simplify_cfg(tcx, body);
}
}
@@ -260,6 +278,18 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> {
}
}
+pub fn simplify_duplicate_switch_targets(terminator: &mut Terminator<'_>) {
+ if let TerminatorKind::SwitchInt { targets, .. } = &mut terminator.kind {
+ let otherwise = targets.otherwise();
+ if targets.iter().any(|t| t.1 == otherwise) {
+ *targets = SwitchTargets::new(
+ targets.iter().filter(|t| t.1 != otherwise),
+ targets.otherwise(),
+ );
+ }
+ }
+}
+
pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
struct OptApplier<'tcx> {
tcx: TyCtxt<'tcx>,
@@ -280,6 +310,8 @@ pub fn remove_duplicate_unreachable_blocks<'tcx>(tcx: TyCtxt<'tcx>, body: &mut B
}
}
+ simplify_duplicate_switch_targets(terminator);
+
self.super_terminator(terminator, location);
}
}
@@ -423,19 +455,17 @@ fn save_unreachable_coverage(
));
}
-pub struct SimplifyLocals {
- label: String,
-}
-
-impl SimplifyLocals {
- pub fn new(label: &str) -> SimplifyLocals {
- SimplifyLocals { label: format!("SimplifyLocals-{}", label) }
- }
+pub enum SimplifyLocals {
+ BeforeConstProp,
+ Final,
}
impl<'tcx> MirPass<'tcx> for SimplifyLocals {
- fn name(&self) -> &str {
- &self.label
+ fn name(&self) -> &'static str {
+ match &self {
+ SimplifyLocals::BeforeConstProp => "SimplifyLocals-before-const-prop",
+ SimplifyLocals::Final => "SimplifyLocals-final",
+ }
}
fn is_enabled(&self, sess: &rustc_session::Session) -> bool {
diff --git a/compiler/rustc_mir_transform/src/simplify_branches.rs b/compiler/rustc_mir_transform/src/simplify_branches.rs
index 8164b3052..1ff488169 100644
--- a/compiler/rustc_mir_transform/src/simplify_branches.rs
+++ b/compiler/rustc_mir_transform/src/simplify_branches.rs
@@ -2,24 +2,21 @@ use crate::MirPass;
use rustc_middle::mir::*;
use rustc_middle::ty::TyCtxt;
-/// A pass that replaces a branch with a goto when its condition is known.
-pub struct SimplifyConstCondition {
- label: String,
-}
-
-impl SimplifyConstCondition {
- pub fn new(label: &str) -> Self {
- SimplifyConstCondition { label: format!("SimplifyConstCondition-{}", label) }
- }
+pub enum SimplifyConstCondition {
+ AfterConstProp,
+ Final,
}
-
+/// A pass that replaces a branch with a goto when its condition is known.
impl<'tcx> MirPass<'tcx> for SimplifyConstCondition {
- fn name(&self) -> &str {
- &self.label
+ fn name(&self) -> &'static str {
+ match self {
+ SimplifyConstCondition::AfterConstProp => "SimplifyConstCondition-after-const-prop",
+ SimplifyConstCondition::Final => "SimplifyConstCondition-final",
+ }
}
fn run_pass(&self, tcx: TyCtxt<'tcx>, body: &mut Body<'tcx>) {
- let param_env = tcx.param_env(body.source.def_id());
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
for block in body.basic_blocks_mut() {
let terminator = block.terminator_mut();
terminator.kind = match terminator.kind {
diff --git a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
index dcad1518e..113ca2fc5 100644
--- a/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
+++ b/compiler/rustc_mir_transform/src/simplify_comparison_integral.rs
@@ -37,7 +37,7 @@ impl<'tcx> MirPass<'tcx> for SimplifyComparisonIntegral {
let opts = helper.find_optimizations();
let mut storage_deads_to_insert = vec![];
let mut storage_deads_to_remove: Vec<(usize, BasicBlock)> = vec![];
- let param_env = tcx.param_env(body.source.def_id());
+ let param_env = tcx.param_env_reveal_all_normalized(body.source.def_id());
for opt in opts {
trace!("SUCCESS: Applying {:?}", opt);
// replace terminator with a switchInt that switches on the integer directly
diff --git a/compiler/rustc_mir_transform/src/sroa.rs b/compiler/rustc_mir_transform/src/sroa.rs
index c798bd053..2d7729129 100644
--- a/compiler/rustc_mir_transform/src/sroa.rs
+++ b/compiler/rustc_mir_transform/src/sroa.rs
@@ -1,6 +1,6 @@
use crate::MirPass;
use rustc_index::bit_set::{BitSet, GrowableBitSet};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::mir::patch::MirPatch;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
diff --git a/compiler/rustc_mir_transform/src/ssa.rs b/compiler/rustc_mir_transform/src/ssa.rs
index be026402d..7a0d3a025 100644
--- a/compiler/rustc_mir_transform/src/ssa.rs
+++ b/compiler/rustc_mir_transform/src/ssa.rs
@@ -1,11 +1,17 @@
+//! We denote as "SSA" the set of locals that verify the following properties:
+//! 1/ They are only assigned-to once, either as a function parameter, or in an assign statement;
+//! 2/ This single assignment dominates all uses;
+//!
+//! As a consequence of rule 2, we consider that borrowed locals are not SSA, even if they are
+//! `Freeze`, as we do not track that the assignment dominates all uses of the borrow.
+
use either::Either;
use rustc_data_structures::graph::dominators::Dominators;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::middle::resolve_bound_vars::Set1;
use rustc_middle::mir::visit::*;
use rustc_middle::mir::*;
-use rustc_middle::ty::{ParamEnv, TyCtxt};
#[derive(Debug)]
pub struct SsaLocals {
@@ -17,57 +23,60 @@ pub struct SsaLocals {
assignment_order: Vec<Local>,
/// Copy equivalence classes between locals. See `copy_classes` for documentation.
copy_classes: IndexVec<Local, Local>,
+ /// Number of "direct" uses of each local, ie. uses that are not dereferences.
+ /// We ignore non-uses (Storage statements, debuginfo).
+ direct_uses: IndexVec<Local, u32>,
}
/// We often encounter MIR bodies with 1 or 2 basic blocks. In those cases, it's unnecessary to
/// actually compute dominators, we can just compare block indices because bb0 is always the first
-/// block, and in any body all other blocks are always always dominated by bb0.
-struct SmallDominators {
- inner: Option<Dominators<BasicBlock>>,
-}
-
-trait DomExt {
- fn dominates(self, _other: Self, dominators: &SmallDominators) -> bool;
+/// block, and in any body all other blocks are always dominated by bb0.
+struct SmallDominators<'a> {
+ inner: Option<&'a Dominators<BasicBlock>>,
}
-impl DomExt for Location {
- fn dominates(self, other: Location, dominators: &SmallDominators) -> bool {
- if self.block == other.block {
- self.statement_index <= other.statement_index
+impl SmallDominators<'_> {
+ fn dominates(&self, first: Location, second: Location) -> bool {
+ if first.block == second.block {
+ first.statement_index <= second.statement_index
+ } else if let Some(inner) = &self.inner {
+ inner.dominates(first.block, second.block)
} else {
- dominators.dominates(self.block, other.block)
+ first.block < second.block
}
}
-}
-impl SmallDominators {
- fn dominates(&self, dom: BasicBlock, node: BasicBlock) -> bool {
- if let Some(inner) = &self.inner { inner.dominates(dom, node) } else { dom < node }
+ fn check_dominates(&mut self, set: &mut Set1<LocationExtended>, loc: Location) {
+ let assign_dominates = match *set {
+ Set1::Empty | Set1::Many => false,
+ Set1::One(LocationExtended::Arg) => true,
+ Set1::One(LocationExtended::Plain(assign)) => {
+ self.dominates(assign.successor_within_block(), loc)
+ }
+ };
+ // We are visiting a use that is not dominated by an assignment.
+ // Either there is a cycle involved, or we are reading for uninitialized local.
+ // Bail out.
+ if !assign_dominates {
+ *set = Set1::Many;
+ }
}
}
impl SsaLocals {
- pub fn new<'tcx>(
- tcx: TyCtxt<'tcx>,
- param_env: ParamEnv<'tcx>,
- body: &Body<'tcx>,
- borrowed_locals: &BitSet<Local>,
- ) -> SsaLocals {
+ pub fn new<'tcx>(body: &Body<'tcx>) -> SsaLocals {
let assignment_order = Vec::with_capacity(body.local_decls.len());
let assignments = IndexVec::from_elem(Set1::Empty, &body.local_decls);
let dominators =
if body.basic_blocks.len() > 2 { Some(body.basic_blocks.dominators()) } else { None };
let dominators = SmallDominators { inner: dominators };
- let mut visitor = SsaVisitor { assignments, assignment_order, dominators };
- for (local, decl) in body.local_decls.iter_enumerated() {
- if matches!(body.local_kind(local), LocalKind::Arg) {
- visitor.assignments[local] = Set1::One(LocationExtended::Arg);
- }
- if borrowed_locals.contains(local) && !decl.ty.is_freeze(tcx, param_env) {
- visitor.assignments[local] = Set1::Many;
- }
+ let direct_uses = IndexVec::from_elem(0, &body.local_decls);
+ let mut visitor = SsaVisitor { assignments, assignment_order, dominators, direct_uses };
+
+ for local in body.args_iter() {
+ visitor.assignments[local] = Set1::One(LocationExtended::Arg);
}
if body.basic_blocks.len() > 2 {
@@ -85,36 +94,52 @@ impl SsaLocals {
}
debug!(?visitor.assignments);
+ debug!(?visitor.direct_uses);
visitor
.assignment_order
.retain(|&local| matches!(visitor.assignments[local], Set1::One(_)));
debug!(?visitor.assignment_order);
- let copy_classes = compute_copy_classes(&visitor, body);
-
- SsaLocals {
+ let mut ssa = SsaLocals {
assignments: visitor.assignments,
assignment_order: visitor.assignment_order,
- copy_classes,
- }
+ direct_uses: visitor.direct_uses,
+ // This is filled by `compute_copy_classes`.
+ copy_classes: IndexVec::default(),
+ };
+ compute_copy_classes(&mut ssa, body);
+ ssa
+ }
+
+ pub fn num_locals(&self) -> usize {
+ self.assignments.len()
+ }
+
+ pub fn locals(&self) -> impl Iterator<Item = Local> {
+ self.assignments.indices()
}
pub fn is_ssa(&self, local: Local) -> bool {
matches!(self.assignments[local], Set1::One(_))
}
+ /// Return the number of uses if a local that are not "Deref".
+ pub fn num_direct_uses(&self, local: Local) -> u32 {
+ self.direct_uses[local]
+ }
+
pub fn assignments<'a, 'tcx>(
&'a self,
body: &'a Body<'tcx>,
- ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>)> + 'a {
+ ) -> impl Iterator<Item = (Local, &'a Rvalue<'tcx>, Location)> + 'a {
self.assignment_order.iter().filter_map(|&local| {
if let Set1::One(LocationExtended::Plain(loc)) = self.assignments[local] {
// `loc` must point to a direct assignment to `local`.
let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
let Some((target, rvalue)) = stmt.kind.as_assign() else { bug!() };
assert_eq!(target.as_local(), Some(local));
- Some((local, rvalue))
+ Some((local, rvalue, loc))
} else {
None
}
@@ -173,48 +198,32 @@ enum LocationExtended {
Arg,
}
-struct SsaVisitor {
- dominators: SmallDominators,
+struct SsaVisitor<'a> {
+ dominators: SmallDominators<'a>,
assignments: IndexVec<Local, Set1<LocationExtended>>,
assignment_order: Vec<Local>,
+ direct_uses: IndexVec<Local, u32>,
}
-impl SsaVisitor {
- fn check_assignment_dominates(&mut self, local: Local, loc: Location) {
- let set = &mut self.assignments[local];
- let assign_dominates = match *set {
- Set1::Empty | Set1::Many => false,
- Set1::One(LocationExtended::Arg) => true,
- Set1::One(LocationExtended::Plain(assign)) => {
- assign.successor_within_block().dominates(loc, &self.dominators)
- }
- };
- // We are visiting a use that is not dominated by an assignment.
- // Either there is a cycle involved, or we are reading for uninitialized local.
- // Bail out.
- if !assign_dominates {
- *set = Set1::Many;
- }
- }
-}
-
-impl<'tcx> Visitor<'tcx> for SsaVisitor {
+impl<'tcx> Visitor<'tcx> for SsaVisitor<'_> {
fn visit_local(&mut self, local: Local, ctxt: PlaceContext, loc: Location) {
match ctxt {
- PlaceContext::MutatingUse(MutatingUseContext::Store) => {
- self.assignments[local].insert(LocationExtended::Plain(loc));
- if let Set1::One(_) = self.assignments[local] {
- // Only record if SSA-like, to avoid growing the vector needlessly.
- self.assignment_order.push(local);
- }
- }
+ PlaceContext::MutatingUse(MutatingUseContext::Projection)
+ | PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection) => bug!(),
// Anything can happen with raw pointers, so remove them.
- PlaceContext::NonMutatingUse(NonMutatingUseContext::AddressOf)
- | PlaceContext::MutatingUse(_) => self.assignments[local] = Set1::Many,
- // Immutable borrows are taken into account in `SsaLocals::new` by
- // removing non-freeze locals.
+ // We do not verify that all uses of the borrow dominate the assignment to `local`,
+ // so we have to remove them too.
+ PlaceContext::NonMutatingUse(
+ NonMutatingUseContext::SharedBorrow
+ | NonMutatingUseContext::ShallowBorrow
+ | NonMutatingUseContext::AddressOf,
+ )
+ | PlaceContext::MutatingUse(_) => {
+ self.assignments[local] = Set1::Many;
+ }
PlaceContext::NonMutatingUse(_) => {
- self.check_assignment_dominates(local, loc);
+ self.dominators.check_dominates(&mut self.assignments[local], loc);
+ self.direct_uses[local] += 1;
}
PlaceContext::NonUse(_) => {}
}
@@ -224,58 +233,113 @@ impl<'tcx> Visitor<'tcx> for SsaVisitor {
if place.projection.first() == Some(&PlaceElem::Deref) {
// Do not do anything for storage statements and debuginfo.
if ctxt.is_use() {
- // A use through a `deref` only reads from the local, and cannot write to it.
- let new_ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Projection);
+ // Only change the context if it is a real use, not a "use" in debuginfo.
+ let new_ctxt = PlaceContext::NonMutatingUse(NonMutatingUseContext::Copy);
self.visit_projection(place.as_ref(), new_ctxt, loc);
- self.check_assignment_dominates(place.local, loc);
+ self.dominators.check_dominates(&mut self.assignments[place.local], loc);
}
return;
+ } else {
+ self.visit_projection(place.as_ref(), ctxt, loc);
+ self.visit_local(place.local, ctxt, loc);
+ }
+ }
+
+ fn visit_assign(&mut self, place: &Place<'tcx>, rvalue: &Rvalue<'tcx>, loc: Location) {
+ if let Some(local) = place.as_local() {
+ self.assignments[local].insert(LocationExtended::Plain(loc));
+ if let Set1::One(_) = self.assignments[local] {
+ // Only record if SSA-like, to avoid growing the vector needlessly.
+ self.assignment_order.push(local);
+ }
+ } else {
+ self.visit_place(place, PlaceContext::MutatingUse(MutatingUseContext::Store), loc);
}
- self.super_place(place, ctxt, loc);
+ self.visit_rvalue(rvalue, loc);
}
}
#[instrument(level = "trace", skip(ssa, body))]
-fn compute_copy_classes(ssa: &SsaVisitor, body: &Body<'_>) -> IndexVec<Local, Local> {
+fn compute_copy_classes(ssa: &mut SsaLocals, body: &Body<'_>) {
+ let mut direct_uses = std::mem::take(&mut ssa.direct_uses);
let mut copies = IndexVec::from_fn_n(|l| l, body.local_decls.len());
- for &local in &ssa.assignment_order {
- debug!(?local);
-
- if local == RETURN_PLACE {
- // `_0` is special, we cannot rename it.
- continue;
- }
-
- // This is not SSA: mark that we don't know the value.
- debug!(assignments = ?ssa.assignments[local]);
- let Set1::One(LocationExtended::Plain(loc)) = ssa.assignments[local] else { continue };
-
- // `loc` must point to a direct assignment to `local`.
- let Either::Left(stmt) = body.stmt_at(loc) else { bug!() };
- let Some((_target, rvalue)) = stmt.kind.as_assign() else { bug!() };
- assert_eq!(_target.as_local(), Some(local));
-
+ for (local, rvalue, _) in ssa.assignments(body) {
let (Rvalue::Use(Operand::Copy(place) | Operand::Move(place)) | Rvalue::CopyForDeref(place))
= rvalue
else { continue };
let Some(rhs) = place.as_local() else { continue };
- let Set1::One(_) = ssa.assignments[rhs] else { continue };
+ if !ssa.is_ssa(rhs) {
+ continue;
+ }
// We visit in `assignment_order`, ie. reverse post-order, so `rhs` has been
// visited before `local`, and we just have to copy the representing local.
- copies[local] = copies[rhs];
+ let head = copies[rhs];
+
+ if local == RETURN_PLACE {
+ // `_0` is special, we cannot rename it. Instead, rename the class of `rhs` to
+ // `RETURN_PLACE`. This is only possible if the class head is a temporary, not an
+ // argument.
+ if body.local_kind(head) != LocalKind::Temp {
+ continue;
+ }
+ for h in copies.iter_mut() {
+ if *h == head {
+ *h = RETURN_PLACE;
+ }
+ }
+ } else {
+ copies[local] = head;
+ }
+ direct_uses[rhs] -= 1;
}
debug!(?copies);
+ debug!(?direct_uses);
// Invariant: `copies` must point to the head of an equivalence class.
#[cfg(debug_assertions)]
for &head in copies.iter() {
assert_eq!(copies[head], head);
}
+ debug_assert_eq!(copies[RETURN_PLACE], RETURN_PLACE);
+
+ ssa.direct_uses = direct_uses;
+ ssa.copy_classes = copies;
+}
+
+#[derive(Debug)]
+pub(crate) struct StorageLiveLocals {
+ /// Set of "StorageLive" statements for each local.
+ storage_live: IndexVec<Local, Set1<LocationExtended>>,
+}
+
+impl StorageLiveLocals {
+ pub(crate) fn new(
+ body: &Body<'_>,
+ always_storage_live_locals: &BitSet<Local>,
+ ) -> StorageLiveLocals {
+ let mut storage_live = IndexVec::from_elem(Set1::Empty, &body.local_decls);
+ for local in always_storage_live_locals.iter() {
+ storage_live[local] = Set1::One(LocationExtended::Arg);
+ }
+ for (block, bbdata) in body.basic_blocks.iter_enumerated() {
+ for (statement_index, statement) in bbdata.statements.iter().enumerate() {
+ if let StatementKind::StorageLive(local) = statement.kind {
+ storage_live[local]
+ .insert(LocationExtended::Plain(Location { block, statement_index }));
+ }
+ }
+ }
+ debug!(?storage_live);
+ StorageLiveLocals { storage_live }
+ }
- copies
+ #[inline]
+ pub(crate) fn has_single_storage(&self, local: Local) -> bool {
+ matches!(self.storage_live[local], Set1::One(_))
+ }
}
diff --git a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
index be0aa0fc4..5389b9f52 100644
--- a/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
+++ b/compiler/rustc_mir_transform/src/uninhabited_enum_branching.rs
@@ -109,7 +109,9 @@ impl<'tcx> MirPass<'tcx> for UninhabitedEnumBranching {
continue;
};
- let layout = tcx.layout_of(tcx.param_env(body.source.def_id()).and(discriminant_ty));
+ let layout = tcx.layout_of(
+ tcx.param_env_reveal_all_normalized(body.source.def_id()).and(discriminant_ty),
+ );
let allowed_variants = if let Ok(layout) = layout {
variant_discriminants(&layout, discriminant_ty, tcx)
diff --git a/compiler/rustc_monomorphize/Cargo.toml b/compiler/rustc_monomorphize/Cargo.toml
index c8af10576..6d3a3bf90 100644
--- a/compiler/rustc_monomorphize/Cargo.toml
+++ b/compiler/rustc_monomorphize/Cargo.toml
@@ -8,11 +8,11 @@ edition = "2021"
[dependencies]
serde = "1"
serde_json = "1"
-smallvec = { version = "1.8.1", features = [ "union", "may_dangle" ] }
tracing = "0.1"
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
diff --git a/compiler/rustc_monomorphize/messages.ftl b/compiler/rustc_monomorphize/messages.ftl
index 6cea6a603..fdd47e6f7 100644
--- a/compiler/rustc_monomorphize/messages.ftl
+++ b/compiler/rustc_monomorphize/messages.ftl
@@ -1,32 +1,32 @@
-monomorphize_recursion_limit =
- reached the recursion limit while instantiating `{$shrunk}`
- .note = `{$def_path_str}` defined here
-
-monomorphize_written_to_path = the full type name has been written to '{$path}'
-
-monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
-
monomorphize_consider_type_length_limit =
consider adding a `#![type_length_limit="{$type_length}"]` attribute to your crate
-monomorphize_fatal_error = {$error_message}
-
-monomorphize_unknown_partition_strategy = unknown partitioning strategy
+monomorphize_couldnt_dump_mono_stats =
+ unexpected error occurred while dumping monomorphization stats: {$error}
-monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
+monomorphize_encountered_error_while_instantiating =
+ the above error was encountered while instantiating `{$formatted_item}`
-monomorphize_unused_generic_params = item has unused generic parameters
+monomorphize_fatal_error = {$error_message}
monomorphize_large_assignments =
moving {$size} bytes
.label = value moved from here
.note = The current maximum size is {$limit}, but it can be customized with the move_size_limit attribute: `#![move_size_limit = "..."]`
-monomorphize_couldnt_dump_mono_stats =
- unexpected error occurred while dumping monomorphization stats: {$error}
+monomorphize_recursion_limit =
+ reached the recursion limit while instantiating `{$shrunk}`
+ .note = `{$def_path_str}` defined here
-monomorphize_encountered_error_while_instantiating =
- the above error was encountered while instantiating `{$formatted_item}`
+monomorphize_symbol_already_defined = symbol `{$symbol}` is already defined
+
+monomorphize_type_length_limit = reached the type-length limit while instantiating `{$shrunk}`
monomorphize_unknown_cgu_collection_mode =
unknown codegen-item collection mode '{$mode}', falling back to 'lazy' mode
+
+monomorphize_unknown_partition_strategy = unknown partitioning strategy
+
+monomorphize_unused_generic_params = item has unused generic parameters
+
+monomorphize_written_to_path = the full type name has been written to '{$path}'
diff --git a/compiler/rustc_monomorphize/src/collector.rs b/compiler/rustc_monomorphize/src/collector.rs
index 7bcff7e07..35b154b7b 100644
--- a/compiler/rustc_monomorphize/src/collector.rs
+++ b/compiler/rustc_monomorphize/src/collector.rs
@@ -185,9 +185,9 @@ use rustc_middle::mir::interpret::{ErrorHandled, GlobalAlloc, Scalar};
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
use rustc_middle::mir::visit::Visitor as MirVisitor;
use rustc_middle::mir::{self, Local, Location};
+use rustc_middle::query::TyCtxtAt;
use rustc_middle::ty::adjustment::{CustomCoerceUnsized, PointerCast};
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::query::TyCtxtAt;
use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts};
use rustc_middle::ty::{
self, GenericParamDefKind, Instance, InstanceDef, Ty, TyCtxt, TypeFoldable, TypeVisitableExt,
@@ -402,7 +402,7 @@ fn collect_roots(tcx: TyCtxt<'_>, mode: MonoItemCollectionMode) -> Vec<MonoItem<
}
/// Collect all monomorphized items reachable from `starting_point`, and emit a note diagnostic if a
-/// post-monorphization error is encountered during a collection step.
+/// post-monomorphization error is encountered during a collection step.
#[instrument(skip(tcx, visited, recursion_depths, recursion_limit, inlining_map), level = "debug")]
fn collect_items_rec<'tcx>(
tcx: TyCtxt<'tcx>,
@@ -677,7 +677,7 @@ impl<'a, 'tcx> MirNeighborCollector<'a, 'tcx> {
self.instance.subst_mir_and_normalize_erasing_regions(
self.tcx,
ty::ParamEnv::reveal_all(),
- value,
+ ty::EarlyBinder(value),
)
}
}
@@ -843,7 +843,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> {
}
}
mir::TerminatorKind::Assert { ref msg, .. } => {
- let lang_item = match msg {
+ let lang_item = match &**msg {
mir::AssertKind::BoundsCheck { .. } => LangItem::PanicBoundsCheck,
_ => LangItem::Panic,
};
@@ -1230,7 +1230,7 @@ impl<'v> RootCollector<'_, 'v> {
DefKind::GlobalAsm => {
debug!(
"RootCollector: ItemKind::GlobalAsm({})",
- self.tcx.def_path_str(id.owner_id.to_def_id())
+ self.tcx.def_path_str(id.owner_id)
);
self.output.push(dummy_spanned(MonoItem::GlobalAsm(id)));
}
diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs
index 5000fb719..ecc50c3f6 100644
--- a/compiler/rustc_monomorphize/src/lib.rs
+++ b/compiler/rustc_monomorphize/src/lib.rs
@@ -10,11 +10,11 @@ extern crate tracing;
extern crate rustc_middle;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::lang_items::LangItem;
-use rustc_macros::fluent_messages;
+use rustc_middle::query::{Providers, TyCtxtAt};
use rustc_middle::traits;
use rustc_middle::ty::adjustment::CustomCoerceUnsized;
-use rustc_middle::ty::query::{Providers, TyCtxtAt};
use rustc_middle::ty::{self, Ty};
mod collector;
@@ -30,8 +30,12 @@ fn custom_coerce_unsize_info<'tcx>(
source_ty: Ty<'tcx>,
target_ty: Ty<'tcx>,
) -> CustomCoerceUnsized {
- let trait_ref =
- ty::Binder::dummy(tcx.mk_trait_ref(LangItem::CoerceUnsized, [source_ty, target_ty]));
+ let trait_ref = ty::Binder::dummy(ty::TraitRef::from_lang_item(
+ tcx.tcx,
+ LangItem::CoerceUnsized,
+ tcx.span,
+ [source_ty, target_ty],
+ ));
match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), trait_ref)) {
Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData {
diff --git a/compiler/rustc_monomorphize/src/partitioning/default.rs b/compiler/rustc_monomorphize/src/partitioning/default.rs
index 482b78d42..603b3ddc1 100644
--- a/compiler/rustc_monomorphize/src/partitioning/default.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/default.rs
@@ -1,3 +1,4 @@
+use std::cmp;
use std::collections::hash_map::Entry;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
@@ -14,19 +15,19 @@ use rustc_span::symbol::Symbol;
use super::PartitioningCx;
use crate::collector::InliningMap;
-use crate::partitioning::merging;
-use crate::partitioning::{
- MonoItemPlacement, Partitioner, PostInliningPartitioning, PreInliningPartitioning,
-};
+use crate::partitioning::{MonoItemPlacement, Partition, PlacedRootMonoItems};
pub struct DefaultPartitioning;
-impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
- fn place_root_mono_items(
+impl<'tcx> Partition<'tcx> for DefaultPartitioning {
+ fn place_root_mono_items<I>(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
- ) -> PreInliningPartitioning<'tcx> {
+ mono_items: &mut I,
+ ) -> PlacedRootMonoItems<'tcx>
+ where
+ I: Iterator<Item = MonoItem<'tcx>>,
+ {
let mut roots = FxHashSet::default();
let mut codegen_units = FxHashMap::default();
let is_incremental_build = cx.tcx.sess.opts.incremental.is_some();
@@ -88,38 +89,120 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
codegen_units.insert(codegen_unit_name, CodegenUnit::new(codegen_unit_name));
}
- PreInliningPartitioning {
- codegen_units: codegen_units.into_values().map(|codegen_unit| codegen_unit).collect(),
- roots,
- internalization_candidates,
- }
+ let codegen_units = codegen_units.into_values().collect();
+ PlacedRootMonoItems { codegen_units, roots, internalization_candidates }
}
fn merge_codegen_units(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+ codegen_units: &mut Vec<CodegenUnit<'tcx>>,
) {
- merging::merge_codegen_units(cx, initial_partitioning);
+ assert!(cx.target_cgu_count >= 1);
+
+ // Note that at this point in time the `codegen_units` here may not be
+ // in a deterministic order (but we know they're deterministically the
+ // same set). We want this merging to produce a deterministic ordering
+ // of codegen units from the input.
+ //
+ // Due to basically how we've implemented the merging below (merge the
+ // two smallest into each other) we're sure to start off with a
+ // deterministic order (sorted by name). This'll mean that if two cgus
+ // have the same size the stable sort below will keep everything nice
+ // and deterministic.
+ codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
+
+ // This map keeps track of what got merged into what.
+ let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> =
+ codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect();
+
+ // Merge the two smallest codegen units until the target size is
+ // reached.
+ while codegen_units.len() > cx.target_cgu_count {
+ // Sort small cgus to the back
+ codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
+ let mut smallest = codegen_units.pop().unwrap();
+ let second_smallest = codegen_units.last_mut().unwrap();
+
+ // Move the mono-items from `smallest` to `second_smallest`
+ second_smallest.modify_size_estimate(smallest.size_estimate());
+ for (k, v) in smallest.items_mut().drain() {
+ second_smallest.items_mut().insert(k, v);
+ }
+
+ // Record that `second_smallest` now contains all the stuff that was
+ // in `smallest` before.
+ let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap();
+ cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names);
+
+ debug!(
+ "CodegenUnit {} merged into CodegenUnit {}",
+ smallest.name(),
+ second_smallest.name()
+ );
+ }
+
+ let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
+
+ if cx.tcx.sess.opts.incremental.is_some() {
+ // If we are doing incremental compilation, we want CGU names to
+ // reflect the path of the source level module they correspond to.
+ // For CGUs that contain the code of multiple modules because of the
+ // merging done above, we use a concatenation of the names of all
+ // contained CGUs.
+ let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents
+ .into_iter()
+ // This `filter` makes sure we only update the name of CGUs that
+ // were actually modified by merging.
+ .filter(|(_, cgu_contents)| cgu_contents.len() > 1)
+ .map(|(current_cgu_name, cgu_contents)| {
+ let mut cgu_contents: Vec<&str> =
+ cgu_contents.iter().map(|s| s.as_str()).collect();
+
+ // Sort the names, so things are deterministic and easy to
+ // predict. We are sorting primitive `&str`s here so we can
+ // use unstable sort.
+ cgu_contents.sort_unstable();
+
+ (current_cgu_name, cgu_contents.join("--"))
+ })
+ .collect();
+
+ for cgu in codegen_units.iter_mut() {
+ if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
+ if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names {
+ cgu.set_name(Symbol::intern(&new_cgu_name));
+ } else {
+ // If we don't require CGU names to be human-readable,
+ // we use a fixed length hash of the composite CGU name
+ // instead.
+ let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
+ cgu.set_name(Symbol::intern(&new_cgu_name));
+ }
+ }
+ }
+ } else {
+ // If we are compiling non-incrementally we just generate simple CGU
+ // names containing an index.
+ for (index, cgu) in codegen_units.iter_mut().enumerate() {
+ let numbered_codegen_unit_name =
+ cgu_name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index));
+ cgu.set_name(numbered_codegen_unit_name);
+ }
+ }
}
fn place_inlined_mono_items(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- initial_partitioning: PreInliningPartitioning<'tcx>,
- ) -> PostInliningPartitioning<'tcx> {
- let mut new_partitioning = Vec::new();
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ roots: FxHashSet<MonoItem<'tcx>>,
+ ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
let mut mono_item_placements = FxHashMap::default();
- let PreInliningPartitioning {
- codegen_units: initial_cgus,
- roots,
- internalization_candidates,
- } = initial_partitioning;
-
- let single_codegen_unit = initial_cgus.len() == 1;
+ let single_codegen_unit = codegen_units.len() == 1;
- for old_codegen_unit in initial_cgus {
+ for old_codegen_unit in codegen_units.iter_mut() {
// Collect all items that need to be available in this codegen unit.
let mut reachable = FxHashSet::default();
for root in old_codegen_unit.items().keys() {
@@ -171,14 +254,10 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
}
}
- new_partitioning.push(new_codegen_unit);
+ *old_codegen_unit = new_codegen_unit;
}
- return PostInliningPartitioning {
- codegen_units: new_partitioning,
- mono_item_placements,
- internalization_candidates,
- };
+ return mono_item_placements;
fn follow_inlining<'tcx>(
mono_item: MonoItem<'tcx>,
@@ -198,14 +277,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
fn internalize_symbols(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- partitioning: &mut PostInliningPartitioning<'tcx>,
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
) {
- if partitioning.codegen_units.len() == 1 {
+ if codegen_units.len() == 1 {
// Fast path for when there is only one codegen unit. In this case we
// can internalize all candidates, since there is nowhere else they
// could be accessed from.
- for cgu in &mut partitioning.codegen_units {
- for candidate in &partitioning.internalization_candidates {
+ for cgu in codegen_units {
+ for candidate in &internalization_candidates {
cgu.items_mut().insert(*candidate, (Linkage::Internal, Visibility::Default));
}
}
@@ -222,15 +303,13 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning {
}
});
- let mono_item_placements = &partitioning.mono_item_placements;
-
// For each internalization candidates in each codegen unit, check if it is
// accessed from outside its defining codegen unit.
- for cgu in &mut partitioning.codegen_units {
+ for cgu in codegen_units {
let home_cgu = MonoItemPlacement::SingleCgu { cgu_name: cgu.name() };
for (accessee, linkage_and_visibility) in cgu.items_mut() {
- if !partitioning.internalization_candidates.contains(accessee) {
+ if !internalization_candidates.contains(accessee) {
// This item is no candidate for internalizing, so skip it.
continue;
}
@@ -267,7 +346,7 @@ fn characteristic_def_id_of_mono_item<'tcx>(
match mono_item {
MonoItem::Fn(instance) => {
let def_id = match instance.def {
- ty::InstanceDef::Item(def) => def.did,
+ ty::InstanceDef::Item(def) => def,
ty::InstanceDef::VTableShim(..)
| ty::InstanceDef::ReifyShim(..)
| ty::InstanceDef::FnPtrShim(..)
@@ -302,12 +381,12 @@ fn characteristic_def_id_of_mono_item<'tcx>(
// When polymorphization is enabled, methods which do not depend on their generic
// parameters, but the self-type of their impl block do will fail to normalize.
- if !tcx.sess.opts.unstable_opts.polymorphize || !instance.needs_subst() {
+ if !tcx.sess.opts.unstable_opts.polymorphize || !instance.has_param() {
// This is a method within an impl, find out what the self-type is:
let impl_self_ty = tcx.subst_and_normalize_erasing_regions(
instance.substs,
ty::ParamEnv::reveal_all(),
- tcx.type_of(impl_def_id).skip_binder(),
+ tcx.type_of(impl_def_id),
);
if let Some(def_id) = characteristic_def_id_of_type(impl_self_ty) {
return Some(def_id);
@@ -421,10 +500,9 @@ fn mono_item_visibility<'tcx>(
};
let def_id = match instance.def {
- InstanceDef::Item(def) => def.did,
- InstanceDef::DropGlue(def_id, Some(_)) => def_id,
+ InstanceDef::Item(def_id) | InstanceDef::DropGlue(def_id, Some(_)) => def_id,
- // We match the visiblity of statics here
+ // We match the visibility of statics here
InstanceDef::ThreadLocalShim(def_id) => {
return static_visibility(tcx, can_be_internalized, def_id);
}
diff --git a/compiler/rustc_monomorphize/src/partitioning/merging.rs b/compiler/rustc_monomorphize/src/partitioning/merging.rs
deleted file mode 100644
index 5c524a184..000000000
--- a/compiler/rustc_monomorphize/src/partitioning/merging.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-use std::cmp;
-
-use rustc_data_structures::fx::FxHashMap;
-use rustc_hir::def_id::LOCAL_CRATE;
-use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder};
-use rustc_span::symbol::Symbol;
-
-use super::PartitioningCx;
-use crate::partitioning::PreInliningPartitioning;
-
-pub fn merge_codegen_units<'tcx>(
- cx: &PartitioningCx<'_, 'tcx>,
- initial_partitioning: &mut PreInliningPartitioning<'tcx>,
-) {
- assert!(cx.target_cgu_count >= 1);
- let codegen_units = &mut initial_partitioning.codegen_units;
-
- // Note that at this point in time the `codegen_units` here may not be in a
- // deterministic order (but we know they're deterministically the same set).
- // We want this merging to produce a deterministic ordering of codegen units
- // from the input.
- //
- // Due to basically how we've implemented the merging below (merge the two
- // smallest into each other) we're sure to start off with a deterministic
- // order (sorted by name). This'll mean that if two cgus have the same size
- // the stable sort below will keep everything nice and deterministic.
- codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
-
- // This map keeps track of what got merged into what.
- let mut cgu_contents: FxHashMap<Symbol, Vec<Symbol>> =
- codegen_units.iter().map(|cgu| (cgu.name(), vec![cgu.name()])).collect();
-
- // Merge the two smallest codegen units until the target size is reached.
- while codegen_units.len() > cx.target_cgu_count {
- // Sort small cgus to the back
- codegen_units.sort_by_cached_key(|cgu| cmp::Reverse(cgu.size_estimate()));
- let mut smallest = codegen_units.pop().unwrap();
- let second_smallest = codegen_units.last_mut().unwrap();
-
- // Move the mono-items from `smallest` to `second_smallest`
- second_smallest.modify_size_estimate(smallest.size_estimate());
- for (k, v) in smallest.items_mut().drain() {
- second_smallest.items_mut().insert(k, v);
- }
-
- // Record that `second_smallest` now contains all the stuff that was in
- // `smallest` before.
- let mut consumed_cgu_names = cgu_contents.remove(&smallest.name()).unwrap();
- cgu_contents.get_mut(&second_smallest.name()).unwrap().append(&mut consumed_cgu_names);
-
- debug!(
- "CodegenUnit {} merged into CodegenUnit {}",
- smallest.name(),
- second_smallest.name()
- );
- }
-
- let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx);
-
- if cx.tcx.sess.opts.incremental.is_some() {
- // If we are doing incremental compilation, we want CGU names to
- // reflect the path of the source level module they correspond to.
- // For CGUs that contain the code of multiple modules because of the
- // merging done above, we use a concatenation of the names of
- // all contained CGUs.
- let new_cgu_names: FxHashMap<Symbol, String> = cgu_contents
- .into_iter()
- // This `filter` makes sure we only update the name of CGUs that
- // were actually modified by merging.
- .filter(|(_, cgu_contents)| cgu_contents.len() > 1)
- .map(|(current_cgu_name, cgu_contents)| {
- let mut cgu_contents: Vec<&str> = cgu_contents.iter().map(|s| s.as_str()).collect();
-
- // Sort the names, so things are deterministic and easy to
- // predict.
-
- // We are sorting primitive &strs here so we can use unstable sort
- cgu_contents.sort_unstable();
-
- (current_cgu_name, cgu_contents.join("--"))
- })
- .collect();
-
- for cgu in codegen_units.iter_mut() {
- if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) {
- if cx.tcx.sess.opts.unstable_opts.human_readable_cgu_names {
- cgu.set_name(Symbol::intern(&new_cgu_name));
- } else {
- // If we don't require CGU names to be human-readable, we
- // use a fixed length hash of the composite CGU name
- // instead.
- let new_cgu_name = CodegenUnit::mangle_name(&new_cgu_name);
- cgu.set_name(Symbol::intern(&new_cgu_name));
- }
- }
- }
- } else {
- // If we are compiling non-incrementally we just generate simple CGU
- // names containing an index.
- for (index, cgu) in codegen_units.iter_mut().enumerate() {
- cgu.set_name(numbered_codegen_unit_name(cgu_name_builder, index));
- }
- }
-}
-
-fn numbered_codegen_unit_name(
- name_builder: &mut CodegenUnitNameBuilder<'_>,
- index: usize,
-) -> Symbol {
- name_builder.build_cgu_name_no_mangle(LOCAL_CRATE, &["cgu"], Some(index))
-}
diff --git a/compiler/rustc_monomorphize/src/partitioning/mod.rs b/compiler/rustc_monomorphize/src/partitioning/mod.rs
index 18aa0742c..d0b23ca9e 100644
--- a/compiler/rustc_monomorphize/src/partitioning/mod.rs
+++ b/compiler/rustc_monomorphize/src/partitioning/mod.rs
@@ -93,7 +93,6 @@
//! inlining, even when they are not marked `#[inline]`.
mod default;
-mod merging;
use std::cmp;
use std::fs::{self, File};
@@ -106,8 +105,8 @@ use rustc_hir::def_id::{DefIdSet, LOCAL_CRATE};
use rustc_middle::mir;
use rustc_middle::mir::mono::MonoItem;
use rustc_middle::mir::mono::{CodegenUnit, Linkage};
+use rustc_middle::query::Providers;
use rustc_middle::ty::print::with_no_trimmed_paths;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{DumpMonoStatsFormat, SwitchWithOptPath};
use rustc_span::symbol::Symbol;
@@ -118,58 +117,135 @@ use crate::errors::{
CouldntDumpMonoStats, SymbolAlreadyDefined, UnknownCguCollectionMode, UnknownPartitionStrategy,
};
-pub struct PartitioningCx<'a, 'tcx> {
+enum Partitioner {
+ Default(default::DefaultPartitioning),
+ // Other partitioning strategies can go here.
+ Unknown,
+}
+
+impl<'tcx> Partition<'tcx> for Partitioner {
+ fn place_root_mono_items<I>(
+ &mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
+ mono_items: &mut I,
+ ) -> PlacedRootMonoItems<'tcx>
+ where
+ I: Iterator<Item = MonoItem<'tcx>>,
+ {
+ match self {
+ Partitioner::Default(partitioner) => partitioner.place_root_mono_items(cx, mono_items),
+ Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
+ }
+ }
+
+ fn merge_codegen_units(
+ &mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
+ codegen_units: &mut Vec<CodegenUnit<'tcx>>,
+ ) {
+ match self {
+ Partitioner::Default(partitioner) => partitioner.merge_codegen_units(cx, codegen_units),
+ Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
+ }
+ }
+
+ fn place_inlined_mono_items(
+ &mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ roots: FxHashSet<MonoItem<'tcx>>,
+ ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement> {
+ match self {
+ Partitioner::Default(partitioner) => {
+ partitioner.place_inlined_mono_items(cx, codegen_units, roots)
+ }
+ Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
+ }
+ }
+
+ fn internalize_symbols(
+ &mut self,
+ cx: &PartitioningCx<'_, 'tcx>,
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+ ) {
+ match self {
+ Partitioner::Default(partitioner) => partitioner.internalize_symbols(
+ cx,
+ codegen_units,
+ mono_item_placements,
+ internalization_candidates,
+ ),
+ Partitioner::Unknown => cx.tcx.sess.emit_fatal(UnknownPartitionStrategy),
+ }
+ }
+}
+
+struct PartitioningCx<'a, 'tcx> {
tcx: TyCtxt<'tcx>,
target_cgu_count: usize,
inlining_map: &'a InliningMap<'tcx>,
}
-trait Partitioner<'tcx> {
- fn place_root_mono_items(
+pub struct PlacedRootMonoItems<'tcx> {
+ codegen_units: Vec<CodegenUnit<'tcx>>,
+ roots: FxHashSet<MonoItem<'tcx>>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+}
+
+trait Partition<'tcx> {
+ fn place_root_mono_items<I>(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
- ) -> PreInliningPartitioning<'tcx>;
+ mono_items: &mut I,
+ ) -> PlacedRootMonoItems<'tcx>
+ where
+ I: Iterator<Item = MonoItem<'tcx>>;
fn merge_codegen_units(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- initial_partitioning: &mut PreInliningPartitioning<'tcx>,
+ codegen_units: &mut Vec<CodegenUnit<'tcx>>,
);
fn place_inlined_mono_items(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- initial_partitioning: PreInliningPartitioning<'tcx>,
- ) -> PostInliningPartitioning<'tcx>;
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ roots: FxHashSet<MonoItem<'tcx>>,
+ ) -> FxHashMap<MonoItem<'tcx>, MonoItemPlacement>;
fn internalize_symbols(
&mut self,
cx: &PartitioningCx<'_, 'tcx>,
- partitioning: &mut PostInliningPartitioning<'tcx>,
+ codegen_units: &mut [CodegenUnit<'tcx>],
+ mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
+ internalization_candidates: FxHashSet<MonoItem<'tcx>>,
);
}
-fn get_partitioner<'tcx>(tcx: TyCtxt<'tcx>) -> Box<dyn Partitioner<'tcx>> {
+fn get_partitioner(tcx: TyCtxt<'_>) -> Partitioner {
let strategy = match &tcx.sess.opts.unstable_opts.cgu_partitioning_strategy {
None => "default",
Some(s) => &s[..],
};
match strategy {
- "default" => Box::new(default::DefaultPartitioning),
- _ => {
- tcx.sess.emit_fatal(UnknownPartitionStrategy);
- }
+ "default" => Partitioner::Default(default::DefaultPartitioning),
+ _ => Partitioner::Unknown,
}
}
-pub fn partition<'tcx>(
+fn partition<'tcx, I>(
tcx: TyCtxt<'tcx>,
- mono_items: &mut dyn Iterator<Item = MonoItem<'tcx>>,
+ mono_items: &mut I,
max_cgu_count: usize,
inlining_map: &InliningMap<'tcx>,
-) -> Vec<CodegenUnit<'tcx>> {
+) -> Vec<CodegenUnit<'tcx>>
+where
+ I: Iterator<Item = MonoItem<'tcx>>,
+{
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning");
let mut partitioner = get_partitioner(tcx);
@@ -177,40 +253,51 @@ pub fn partition<'tcx>(
// In the first step, we place all regular monomorphizations into their
// respective 'home' codegen unit. Regular monomorphizations are all
// functions and statics defined in the local crate.
- let mut initial_partitioning = {
+ let PlacedRootMonoItems { mut codegen_units, roots, internalization_candidates } = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_roots");
partitioner.place_root_mono_items(cx, mono_items)
};
- initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx));
+ for cgu in &mut codegen_units {
+ cgu.create_size_estimate(tcx);
+ }
- debug_dump(tcx, "INITIAL PARTITIONING:", initial_partitioning.codegen_units.iter());
+ debug_dump(tcx, "INITIAL PARTITIONING", &codegen_units);
// Merge until we have at most `max_cgu_count` codegen units.
+ // `merge_codegen_units` is responsible for updating the CGU size
+ // estimates.
{
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_merge_cgus");
- partitioner.merge_codegen_units(cx, &mut initial_partitioning);
- debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter());
+ partitioner.merge_codegen_units(cx, &mut codegen_units);
+ debug_dump(tcx, "POST MERGING", &codegen_units);
}
// In the next step, we use the inlining map to determine which additional
// monomorphizations have to go into each codegen unit. These additional
// monomorphizations can be drop-glue, functions from external crates, and
// local functions the definition of which is marked with `#[inline]`.
- let mut post_inlining = {
+ let mono_item_placements = {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_place_inline_items");
- partitioner.place_inlined_mono_items(cx, initial_partitioning)
+ partitioner.place_inlined_mono_items(cx, &mut codegen_units, roots)
};
- post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.create_size_estimate(tcx));
+ for cgu in &mut codegen_units {
+ cgu.create_size_estimate(tcx);
+ }
- debug_dump(tcx, "POST INLINING:", post_inlining.codegen_units.iter());
+ debug_dump(tcx, "POST INLINING", &codegen_units);
// Next we try to make as many symbols "internal" as possible, so LLVM has
// more freedom to optimize.
if !tcx.sess.link_dead_code() {
let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols");
- partitioner.internalize_symbols(cx, &mut post_inlining);
+ partitioner.internalize_symbols(
+ cx,
+ &mut codegen_units,
+ mono_item_placements,
+ internalization_candidates,
+ );
}
let instrument_dead_code =
@@ -218,7 +305,7 @@ pub fn partition<'tcx>(
if instrument_dead_code {
assert!(
- post_inlining.codegen_units.len() > 0,
+ codegen_units.len() > 0,
"There must be at least one CGU that code coverage data can be generated in."
);
@@ -229,7 +316,7 @@ pub fn partition<'tcx>(
// the object file (CGU) containing the dead function stubs is included
// in the final binary. This will probably require forcing these
// function symbols to be included via `-u` or `/include` linker args.
- let mut cgus: Vec<_> = post_inlining.codegen_units.iter_mut().collect();
+ let mut cgus: Vec<_> = codegen_units.iter_mut().collect();
cgus.sort_by_key(|cgu| cgu.size_estimate());
let dead_code_cgu =
@@ -240,27 +327,17 @@ pub fn partition<'tcx>(
} else {
// If there are no CGUs that have externally linked items,
// then we just pick the first CGU as a fallback.
- &mut post_inlining.codegen_units[0]
+ &mut codegen_units[0]
};
dead_code_cgu.make_code_coverage_dead_code_cgu();
}
// Finally, sort by codegen unit name, so that we get deterministic results.
- let PostInliningPartitioning {
- codegen_units: mut result,
- mono_item_placements: _,
- internalization_candidates: _,
- } = post_inlining;
+ codegen_units.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
- result.sort_by(|a, b| a.name().as_str().cmp(b.name().as_str()));
+ debug_dump(tcx, "FINAL", &codegen_units);
- result
-}
-
-pub struct PreInliningPartitioning<'tcx> {
- codegen_units: Vec<CodegenUnit<'tcx>>,
- roots: FxHashSet<MonoItem<'tcx>>,
- internalization_candidates: FxHashSet<MonoItem<'tcx>>,
+ codegen_units
}
/// For symbol internalization, we need to know whether a symbol/mono-item is
@@ -272,39 +349,37 @@ enum MonoItemPlacement {
MultipleCgus,
}
-struct PostInliningPartitioning<'tcx> {
- codegen_units: Vec<CodegenUnit<'tcx>>,
- mono_item_placements: FxHashMap<MonoItem<'tcx>, MonoItemPlacement>,
- internalization_candidates: FxHashSet<MonoItem<'tcx>>,
-}
-
-fn debug_dump<'a, 'tcx, I>(tcx: TyCtxt<'tcx>, label: &str, cgus: I)
-where
- I: Iterator<Item = &'a CodegenUnit<'tcx>>,
- 'tcx: 'a,
-{
+fn debug_dump<'a, 'tcx: 'a>(tcx: TyCtxt<'tcx>, label: &str, cgus: &[CodegenUnit<'tcx>]) {
let dump = move || {
use std::fmt::Write;
+ let num_cgus = cgus.len();
+ let max = cgus.iter().map(|cgu| cgu.size_estimate()).max().unwrap();
+ let min = cgus.iter().map(|cgu| cgu.size_estimate()).min().unwrap();
+ let ratio = max as f64 / min as f64;
+
let s = &mut String::new();
- let _ = writeln!(s, "{label}");
+ let _ = writeln!(
+ s,
+ "{label} ({num_cgus} CodegenUnits, max={max}, min={min}, max/min={ratio:.1}):"
+ );
for cgu in cgus {
let _ =
- writeln!(s, "CodegenUnit {} estimated size {} :", cgu.name(), cgu.size_estimate());
+ writeln!(s, "CodegenUnit {} estimated size {}:", cgu.name(), cgu.size_estimate());
for (mono_item, linkage) in cgu.items() {
let symbol_name = mono_item.symbol_name(tcx).name;
let symbol_hash_start = symbol_name.rfind('h');
let symbol_hash = symbol_hash_start.map_or("<no hash>", |i| &symbol_name[i..]);
- let _ = writeln!(
+ let _ = with_no_trimmed_paths!(writeln!(
s,
" - {} [{:?}] [{}] estimated size {}",
mono_item,
linkage,
symbol_hash,
mono_item.size_estimate(tcx)
- );
+ ));
}
let _ = writeln!(s);
@@ -380,7 +455,7 @@ fn collect_and_partition_mono_items(tcx: TyCtxt<'_>, (): ()) -> (&DefIdSet, &[Co
|| {
let mut codegen_units = partition(
tcx,
- &mut items.iter().cloned(),
+ &mut items.iter().copied(),
tcx.sess.codegen_units(),
&inlining_map,
);
diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs
index 63263a642..88a3e0285 100644
--- a/compiler/rustc_monomorphize/src/polymorphize.rs
+++ b/compiler/rustc_monomorphize/src/polymorphize.rs
@@ -11,9 +11,9 @@ use rustc_middle::mir::{
visit::{TyContext, Visitor},
Constant, ConstantKind, Local, LocalDecl, Location,
};
+use rustc_middle::query::Providers;
use rustc_middle::ty::{
self,
- query::Providers,
subst::SubstsRef,
visit::{TypeSuperVisitable, TypeVisitable, TypeVisitableExt, TypeVisitor},
Const, Ty, TyCtxt, UnusedGenericParams,
@@ -232,7 +232,7 @@ impl<'a, 'tcx> MarkUsedGenericParams<'a, 'tcx> {
/// a closure, generator or constant).
#[instrument(level = "debug", skip(self, def_id, substs))]
fn visit_child_body(&mut self, def_id: DefId, substs: SubstsRef<'tcx>) {
- let instance = ty::InstanceDef::Item(ty::WithOptConstParam::unknown(def_id));
+ let instance = ty::InstanceDef::Item(def_id);
let unused = self.tcx.unused_generic_params(instance);
debug!(?self.unused_parameters, ?unused);
for (i, arg) in substs.iter().enumerate() {
@@ -272,10 +272,10 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> {
// Avoid considering `T` unused when constants are of the form:
// `<Self as Foo<T>>::foo::promoted[p]`
if let Some(p) = promoted {
- if self.def_id == def.did && !self.tcx.generics_of(def.did).has_self {
+ if self.def_id == def && !self.tcx.generics_of(def).has_self {
// If there is a promoted, don't look at the substs - since it will always contain
// the generic parameters, instead, traverse the promoted MIR.
- let promoted = self.tcx.promoted_mir(def.did);
+ let promoted = self.tcx.promoted_mir(def);
self.visit_body(&promoted[p]);
}
}
@@ -305,9 +305,9 @@ impl<'a, 'tcx> TypeVisitor<TyCtxt<'tcx>> for MarkUsedGenericParams<'a, 'tcx> {
ControlFlow::Continue(())
}
ty::ConstKind::Unevaluated(ty::UnevaluatedConst { def, substs })
- if matches!(self.tcx.def_kind(def.did), DefKind::AnonConst) =>
+ if matches!(self.tcx.def_kind(def), DefKind::AnonConst) =>
{
- self.visit_child_body(def.did, substs);
+ self.visit_child_body(def, substs);
ControlFlow::Continue(())
}
_ => c.super_visit_with(self),
diff --git a/compiler/rustc_monomorphize/src/util.rs b/compiler/rustc_monomorphize/src/util.rs
index 33e1f6ce3..d12bfc6f6 100644
--- a/compiler/rustc_monomorphize/src/util.rs
+++ b/compiler/rustc_monomorphize/src/util.rs
@@ -29,12 +29,12 @@ pub(crate) fn dump_closure_profile<'tcx>(tcx: TyCtxt<'tcx>, closure_instance: In
let before_feature_tys = tcx.subst_and_normalize_erasing_regions(
closure_instance.substs,
param_env,
- before_feature_tys,
+ ty::EarlyBinder(before_feature_tys),
);
let after_feature_tys = tcx.subst_and_normalize_erasing_regions(
closure_instance.substs,
param_env,
- after_feature_tys,
+ ty::EarlyBinder(after_feature_tys),
);
let new_size = tcx
diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml
index 3eb158c81..1bd9f6629 100644
--- a/compiler/rustc_parse/Cargo.toml
+++ b/compiler/rustc_parse/Cargo.toml
@@ -12,6 +12,7 @@ rustc_ast_pretty = { path = "../rustc_ast_pretty" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_lexer = { path = "../rustc_lexer" }
rustc_macros = { path = "../rustc_macros" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_parse/messages.ftl b/compiler/rustc_parse/messages.ftl
index f11d0ed0f..926339450 100644
--- a/compiler/rustc_parse/messages.ftl
+++ b/compiler/rustc_parse/messages.ftl
@@ -1,230 +1,298 @@
-parse_struct_literal_body_without_path =
- struct literal body without path
- .suggestion = you might have forgotten to add the struct literal inside the block
+parse_add_paren = try adding parentheses
-parse_struct_literal_needing_parens =
- invalid struct literal
- .suggestion = you might need to surround the struct literal in parentheses
+parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
+ .suggestion = if you meant to call a macro, try
+ .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
-parse_maybe_report_ambiguous_plus =
- ambiguous `+` in a type
- .suggestion = use parentheses to disambiguate
+parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
+ .suggestion = add parentheses to clarify the precedence
-parse_maybe_recover_from_bad_type_plus =
- expected a path on the left-hand side of `+`, not `{$ty}`
+parse_array_brackets_instead_of_braces = this is a block expression, not an array
+ .suggestion = to make an array, use square brackets instead of curly braces
-parse_add_paren = try adding parentheses
+parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
-parse_forgot_paren = perhaps you forgot parentheses?
+parse_assoc_lifetime = associated lifetimes are not supported
+ .label = the lifetime is given here
+ .help = if you meant to specify a trait object, write `dyn Trait + 'lifetime`
-parse_expect_path = expected a path
+parse_associated_static_item_not_allowed = associated `static` items are not allowed
-parse_maybe_recover_from_bad_qpath_stage_2 =
- missing angle brackets in associated item path
- .suggestion = try: `{$ty}`
+parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
-parse_incorrect_semicolon =
- expected item, found `;`
- .suggestion = remove this semicolon
- .help = {$name} declarations are not followed by a semicolon
+parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
+ .label = to use `async fn`, switch to Rust 2018 or later
-parse_incorrect_use_of_await =
- incorrect use of `await`
- .parentheses_suggestion = `await` is not a method call, remove the parentheses
- .postfix_suggestion = `await` is a postfix operation
+parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
+ .suggestion = try switching the order
-parse_in_in_typo =
- expected iterable, found keyword `in`
- .suggestion = remove the duplicated `in`
+parse_attr_after_generic = trailing attribute after generic parameter
+ .label = attributes must go before parameters
-parse_invalid_variable_declaration =
- invalid variable declaration
+parse_attr_without_generics = attribute without generic parameters
+ .label = attributes are only permitted when preceding parameters
-parse_switch_mut_let_order =
- switch the order of `mut` and `let`
-parse_missing_let_before_mut = missing keyword
-parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
-parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
+ .label = attributes are not allowed here
-parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
- .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
- .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
+parse_bad_assoc_type_bounds = bounds on associated types do not belong here
+ .label = belongs in `where` clause
-parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
- .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
- .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
- .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+parse_bad_item_kind = {$descr} is not supported in {$ctx}
+ .help = consider moving the {$descr} out to a nearby module scope
-parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
- .suggestion = use `!` to perform bitwise not
+parse_bad_return_type_notation_dotdot =
+ return type notation uses `()` instead of `(..)` for elided arguments
+ .suggestion = remove the `..`
-parse_unexpected_if_with_if = unexpected `if` in the condition expression
- .suggestion = remove the `if`
+parse_bad_return_type_notation_output =
+ return type not allowed with return type notation
+ .suggestion = remove the return type
-parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
-parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
-parse_unexpected_token_after_not_logical = use `!` to perform logical negation
-parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
+parse_bare_cr = {$double_quotes ->
+ [true] bare CR not allowed in string, use `\r` instead
+ *[false] character constant must be escaped: `\r`
+ }
+ .escape = escape the character
-parse_malformed_loop_label = malformed loop label
- .suggestion = use the correct loop label format
+parse_bare_cr_in_raw_string = bare CR not allowed in raw string
-parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
- .suggestion = remove the lifetime annotation
- .label = annotated with lifetime here
+parse_binary_float_literal_not_supported = binary float literal is not supported
+parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
-parse_field_expression_with_generic = field expressions cannot have generic arguments
+parse_box_not_pat = expected pattern, found {$descr}
+ .note = `box` is a reserved keyword
+ .suggestion = escape `box` to use it as an identifier
-parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
+parse_box_syntax_removed = `box_syntax` has been removed
+ .suggestion = use `Box::new()` instead
-parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
- .suggestion_remove_label = consider removing the label
- .suggestion_enclose_in_block = consider enclosing expression in a block
+parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
-parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
- .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
- .label = the label
- .suggestion = add `:` after the label
+parse_catch_after_try = keyword `catch` cannot follow a `try` block
+ .help = try using `match` on the result of the `try` block instead
+
+parse_cfg_attr_bad_delim = wrong `cfg_attr` delimiters
+parse_colon_as_semi = statements are terminated with a semicolon
+ .suggestion = use a semicolon instead
+
+parse_comma_after_base_struct = cannot use a comma after the base struct
+ .note = the base struct must always be the last field
+ .suggestion = remove this comma
+
+parse_comparison_interpreted_as_generic =
+ `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
+ .label_args = interpreted as generic arguments
+ .label_comparison = not interpreted as comparison
+ .suggestion = try comparing the cast value
+
+parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
+ .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
+ .sugg_split_comparison = split the comparison into two
+ .sugg_parenthesize = parenthesize the comparison
+parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
+ .suggestion = initialize the variable
+ .help = if you meant to overwrite, remove the `let` binding
+
+parse_const_bounds_missing_tilde = const bounds must start with `~`
+ .suggestion = add `~`
+
+parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
+ .suggestion = enclose the `const` expression in braces
+
+parse_const_global_cannot_be_mutable = const globals cannot be mutable
+ .label = cannot be mutable
+ .suggestion = you might want to declare a static instead
+
+parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
+ .suggestion = remove `let`
+
+parse_cr_doc_comment = bare CR not allowed in {$block ->
+ [true] block doc-comment
+ *[false] doc-comment
+}
+
+parse_default_not_followed_by_item = `default` is not followed by an item
+ .label = the `default` qualifier
+ .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
parse_do_catch_syntax_removed = found removed `do catch` syntax
.note = following RFC #2388, the new non-placeholder syntax is `try`
.suggestion = replace with the new syntax
-parse_float_literal_requires_integer_part = float literals must have an integer part
- .suggestion = must have an integer part
+parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
+ .help = doc comments must come before what they document, if a comment was intended use `//`
+ .suggestion = missing comma here
-parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
- .help = valid widths are 8, 16, 32, 64 and 128
+parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
+ .label = doc comments are not allowed here
-parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
- .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
- .suggestion = try making the prefix lowercase
+parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
+ .suggestion = to omit remaining fields, use `..`
-parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
- .label = invalid suffix `{$suffix}`
- .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
+ .suggestion = use `..=` instead
-parse_invalid_float_literal_width = invalid width `{$width}` for float literal
- .help = valid widths are 32 and 64
+parse_dotdotdot = unexpected token: `...`
+ .suggest_exclusive_range = use `..` for an exclusive range
+ .suggest_inclusive_range = or `..=` for an inclusive range
-parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
- .label = invalid suffix `{$suffix}`
- .help = valid suffixes are `f32` and `f64`
+parse_dotdotdot_rest_pattern = unexpected `...`
+ .label = not a valid pattern
+ .suggestion = for a rest pattern, use `..` instead of `...`
-parse_int_literal_too_large = integer literal is too large
+parse_double_colon_in_bound = expected `:` followed by trait or lifetime
+ .suggestion = use single colon
-parse_missing_semicolon_before_array = expected `;`, found `[`
- .suggestion = consider adding `;` here
+parse_dyn_after_mut = `mut` must precede `dyn`
+ .suggestion = place `mut` before `dyn`
-parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
- .label = the `block` fragment is within this context
+parse_empty_exponent_float = expected at least one digit in exponent
-parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
- .suggestion = use `..` to fill in the rest of the fields
+parse_empty_unicode_escape = empty unicode escape
+ .label = this escape must have at least 1 hex digit
-parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
- .add_then_block = add a block here
- .condition_possibly_unfinished = this binary operation is possibly unfinished
+parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
-parse_if_expression_missing_condition = missing condition for `if` expression
- .condition_label = expected condition here
- .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
+parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
+ .suggestion = replace `enum struct` with
-parse_expected_expression_found_let = expected expression, found `let` statement
+parse_eq_field_init = expected `:`, found `=`
+ .suggestion = replace equals symbol with a colon
+
+parse_equals_struct_default = default values on `struct` fields aren't supported
+ .suggestion = remove this unsupported default value
+
+parse_escape_only_char = {$byte ->
+ [true] byte
+ *[false] character
+ } constant must be escaped: `{$escaped_msg}`
+ .escape = escape the character
+
+parse_expect_dotdot_not_dotdotdot = expected `..`, found `...`
+ .suggestion = use `..` to fill in the rest of the fields
parse_expect_eq_instead_of_eqeq = expected `=`, found `==`
.suggestion = consider using `=` here
+parse_expect_label_found_ident = expected a label, found an identifier
+ .suggestion = labels start with a tick
+
+parse_expect_path = expected a path
+
+parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
+ .label_lhs = interpreted as a pattern, not a binding
+ .label_rhs = also a pattern
+ .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
+
+parse_expected_builtin_ident = expected identifier after `builtin #`
+
+parse_expected_comma_after_pattern_field = expected `,`
+
parse_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
-parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
- .branch_label = the attributes are attached to this branch
- .ctx_label = the branch belongs to this `{$ctx}`
- .suggestion = remove the attributes
+parse_expected_expression_found_let = expected expression, found `let` statement
-parse_missing_in_in_for_loop = missing `in` in `for` loop
- .use_in_not_of = try using `in` here instead
- .add_in = try adding `in` here
+parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
+ .suggestion = use `Fn` to refer to the trait
-parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
- .suggestion = try adding an expression to the `for` loop
+parse_expected_identifier = expected identifier
-parse_loop_else = `{$loop_kind}...else` loops are not supported
- .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
- .loop_keyword = `else` is attached to this loop
+parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
+parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
+parse_expected_identifier_found_keyword = expected identifier, found keyword
+parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
+parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
+parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
+parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
+parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
+parse_expected_identifier_found_str = expected identifier, found `{$token}`
-parse_missing_comma_after_match_arm = expected `,` following `match` arm
- .suggestion = missing a comma here to end this `match` arm
+parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
+ .suggestion = add `mut` or `const` here
-parse_catch_after_try = keyword `catch` cannot follow a `try` block
- .help = try using `match` on the result of the `try` block instead
+parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
+parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
+parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
+parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
+parse_expected_semi_found_str = expected `;`, found `{$token}`
-parse_comma_after_base_struct = cannot use a comma after the base struct
- .note = the base struct must always be the last field
- .suggestion = remove this comma
+parse_expected_statement_after_outer_attr = expected statement after outer attribute
-parse_eq_field_init = expected `:`, found `=`
- .suggestion = replace equals symbol with a colon
+parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
-parse_dotdotdot = unexpected token: `...`
- .suggest_exclusive_range = use `..` for an exclusive range
- .suggest_inclusive_range = or `..=` for an inclusive range
+parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
+ .label = dash-separated idents are not valid
+ .suggestion = if the original crate name uses dashes you need to use underscores in the code
-parse_left_arrow_operator = unexpected token: `<-`
- .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
+parse_extern_item_cannot_be_const = extern items cannot be `const`
+ .suggestion = try using a static value
+ .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
-parse_remove_let = expected pattern, found `let`
- .suggestion = remove the unnecessary `let` keyword
+parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
-parse_use_eq_instead = unexpected `==`
- .suggestion = try using `=` instead
+parse_extra_impl_keyword_in_trait_impl = unexpected `impl` keyword
+ .suggestion = remove the extra `impl`
+ .note = this is parsed as an `impl Trait` type, but a trait is expected at this position
-parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
- .suggestion = try using { "`{}`" } instead
-parse_comparison_interpreted_as_generic =
- `<` is interpreted as a start of generic arguments for `{$type}`, not a comparison
- .label_args = interpreted as generic arguments
- .label_comparison = not interpreted as comparison
- .suggestion = try comparing the cast value
+parse_field_expression_with_generic = field expressions cannot have generic arguments
-parse_shift_interpreted_as_generic =
- `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
- .label_args = interpreted as generic arguments
- .label_comparison = not interpreted as shift
- .suggestion = try shifting the cast value
+parse_float_literal_requires_integer_part = float literals must have an integer part
+ .suggestion = must have an integer part
+
+parse_float_literal_unsupported_base = {$base} float literal is not supported
+
+parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
+ .label = `async` because of this
+ .suggestion = remove the `async` qualifier
+
+parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
+ .label = `const` because of this
+ .suggestion = remove the `const` qualifier
+
+parse_fn_ptr_with_generics = function pointer types may not have generic parameters
+ .suggestion = consider moving the lifetime {$arity ->
+ [one] parameter
+ *[other] parameters
+ } to {$for_param_list_exists ->
+ [true] the
+ *[false] a
+ } `for` parameter list
+
+parse_forgot_paren = perhaps you forgot parentheses?
parse_found_expr_would_be_stmt = expected expression, found `{$token}`
.label = expected expression
-parse_leading_plus_not_supported = leading `+` is not supported
- .label = unexpected `+`
- .suggestion_remove_plus = try removing the `+`
+parse_function_body_equals_expr = function body cannot be `= expression;`
+ .suggestion = surround the expression with `{"{"}` and `{"}"}` instead of `=` and `;`
-parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
- .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
- .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
+parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
+ .suggestion = surround the type parameters with angle brackets
-parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
+parse_generics_in_path = unexpected generic arguments in path
-parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
+parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
+parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
+parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+parse_if_expression_missing_condition = missing condition for `if` expression
+ .condition_label = expected condition here
+ .block_label = if this block is the condition of the `if` expression, then it must be followed by another block
-parse_array_brackets_instead_of_braces = this is a block expression, not an array
- .suggestion = to make an array, use square brackets instead of curly braces
+parse_if_expression_missing_then_block = this `if` expression is missing a block after the condition
+ .add_then_block = add a block here
+ .condition_possibly_unfinished = this binary operation is possibly unfinished
-parse_match_arm_body_without_braces = `match` arm body without braces
- .label_statements = {$num_statements ->
- [one] this statement is not surrounded by a body
- *[other] these statements are not surrounded by a body
- }
- .label_arrow = while parsing the `match` arm starting here
- .suggestion_add_braces = surround the {$num_statements ->
- [one] statement
- *[other] statements
- } with a body
- .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
+parse_in_in_typo =
+ expected iterable, found keyword `in`
+ .suggestion = remove the duplicated `in`
+
+parse_inappropriate_default = {$article} {$descr} cannot be `default`
+ .label = `default` because of this
+ .note = only associated `fn`, `const`, and `type` items can be `default`
parse_inclusive_range_extra_equals = unexpected `=` after inclusive range
.suggestion_remove_eq = use `..=` instead
@@ -238,32 +306,18 @@ parse_inclusive_range_no_end = inclusive range with no end
.suggestion_open_range = use `..` instead
.note = inclusive ranges must be bounded at the end (`..=b` or `a..=b`)
-parse_struct_literal_not_allowed_here = struct literals are not allowed here
- .suggestion = surround the struct literal with parentheses
-
-parse_invalid_interpolated_expression = invalid interpolated expression
-
-parse_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
-parse_octal_float_literal_not_supported = octal float literal is not supported
-parse_binary_float_literal_not_supported = binary float literal is not supported
-parse_not_supported = not supported
+parse_incorrect_braces_trait_bounds = incorrect braces around trait bounds
+ .suggestion = remove the parentheses
-parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
- .label = invalid suffix `{$suffix}`
-
-parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
- .label = invalid suffix `{$suffix}`
- .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
- .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
- .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
-
-parse_non_string_abi_literal = non-string ABI literal
- .suggestion = specify the ABI with a string literal
+parse_incorrect_semicolon =
+ expected item, found `;`
+ .suggestion = remove this semicolon
+ .help = {$name} declarations are not followed by a semicolon
-parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
- .label_unmatched = mismatched closing delimiter
- .label_opening_candidate = closing delimiter possibly meant for this
- .label_unclosed = unclosed delimiter
+parse_incorrect_use_of_await =
+ incorrect use of `await`
+ .parentheses_suggestion = `await` is not a method call, remove the parentheses
+ .postfix_suggestion = `await` is a postfix operation
parse_incorrect_visibility_restriction = incorrect visibility restriction
.help = some possible visibility restrictions are:
@@ -272,36 +326,8 @@ parse_incorrect_visibility_restriction = incorrect visibility restriction
`pub(in path::to::module)`: visible only on the specified path
.suggestion = make this visible only to module `{$inner_str}` with `in`
-parse_assignment_else_not_allowed = <assignment> ... else {"{"} ... {"}"} is not allowed
-
-parse_expected_statement_after_outer_attr = expected statement after outer attribute
-
-parse_doc_comment_does_not_document_anything = found a documentation comment that doesn't document anything
- .help = doc comments must come before what they document, if a comment was intended use `//`
- .suggestion = missing comma here
-
-parse_const_let_mutually_exclusive = `const` and `let` are mutually exclusive
- .suggestion = remove `let`
-
-parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
-parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
-parse_extra_if_in_let_else = remove the `if` if you meant to write a `let...else` statement
-
-parse_compound_assignment_expression_in_let = can't reassign to an uninitialized variable
- .suggestion = initialize the variable
- .help = if you meant to overwrite, remove the `let` binding
-
-parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
- .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-
-parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
-
-parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
-parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
-
-parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
- .label_attr = not permitted following an outer doc comment
- .label_prev_doc_comment = previous doc comment
+parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
+parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
@@ -311,139 +337,189 @@ parse_inner_attr_not_permitted_after_outer_attr = an inner attribute is not perm
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-parse_inner_attr_not_permitted = an inner attribute is not permitted in this context
+parse_inner_attr_not_permitted_after_outer_doc_comment = an inner attribute is not permitted following an outer doc comment
+ .label_attr = not permitted following an outer doc comment
+ .label_prev_doc_comment = previous doc comment
.label_does_not_annotate_this = {parse_label_inner_attr_does_not_annotate_this}
.sugg_change_inner_to_outer = {parse_sugg_change_inner_attr_to_outer}
-parse_inner_attr_explanation = inner attributes, like `#![no_std]`, annotate the item enclosing them, and are usually found at the beginning of source files
-parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
-
parse_inner_doc_comment_not_permitted = expected outer doc comment
.note = inner doc comments like this (starting with `//!` or `/*!`) can only appear before items
.suggestion = you might have meant to write a regular comment
.label_does_not_annotate_this = the inner doc comment doesn't annotate this {$item}
.sugg_change_inner_to_outer = to annotate the {$item}, change the doc comment from inner to outer style
-parse_expected_identifier_found_reserved_identifier_str = expected identifier, found reserved identifier `{$token}`
-parse_expected_identifier_found_keyword_str = expected identifier, found keyword `{$token}`
-parse_expected_identifier_found_reserved_keyword_str = expected identifier, found reserved keyword `{$token}`
-parse_expected_identifier_found_doc_comment_str = expected identifier, found doc comment `{$token}`
-parse_expected_identifier_found_str = expected identifier, found `{$token}`
+parse_int_literal_too_large = integer literal is too large
-parse_expected_identifier_found_reserved_identifier = expected identifier, found reserved identifier
-parse_expected_identifier_found_keyword = expected identifier, found keyword
-parse_expected_identifier_found_reserved_keyword = expected identifier, found reserved keyword
-parse_expected_identifier_found_doc_comment = expected identifier, found doc comment
-parse_expected_identifier = expected identifier
+parse_invalid_block_macro_segment = cannot use a `block` macro fragment here
+ .label = the `block` fragment is within this context
-parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
+parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
+ .label = {parse_invalid_char_in_escape_msg}
-parse_sugg_remove_comma = remove this comma
+parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
+ [true] numeric character
+ *[false] unicode
+ } escape
-parse_expected_semi_found_reserved_identifier_str = expected `;`, found reserved identifier `{$token}`
-parse_expected_semi_found_keyword_str = expected `;`, found keyword `{$token}`
-parse_expected_semi_found_reserved_keyword_str = expected `;`, found reserved keyword `{$token}`
-parse_expected_semi_found_doc_comment_str = expected `;`, found doc comment `{$token}`
-parse_expected_semi_found_str = expected `;`, found `{$token}`
+parse_invalid_comparison_operator = invalid comparison operator `{$invalid}`
+ .use_instead = `{$invalid}` is not a valid comparison operator, use `{$correct}`
+ .spaceship_operator_invalid = `<=>` is not a valid comparison operator, use `std::cmp::Ordering`
-parse_sugg_change_this_to_semi = change this to `;`
-parse_sugg_add_semi = add `;` here
-parse_label_unexpected_token = unexpected token
+parse_invalid_curly_in_let_else = right curly brace `{"}"}` before `else` in a `let...else` statement not allowed
+parse_invalid_digit_literal = invalid digit for a base {$base} literal
-parse_unmatched_angle_brackets = {$num_extra_brackets ->
- [one] unmatched angle bracket
- *[other] unmatched angle brackets
+parse_invalid_dyn_keyword = invalid `dyn` keyword
+ .help = `dyn` is only needed at the start of a trait `+`-separated list
+ .suggestion = remove this keyword
+
+parse_invalid_expression_in_let_else = a `{$operator}` expression cannot be directly assigned in `let...else`
+parse_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+ .label = invalid suffix `{$suffix}`
+ .help = valid suffixes are `f32` and `f64`
+
+parse_invalid_float_literal_width = invalid width `{$width}` for float literal
+ .help = valid widths are 32 and 64
+
+parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
+
+parse_invalid_int_literal_width = invalid width `{$width}` for integer literal
+ .help = valid widths are 8, 16, 32, 64 and 128
+
+parse_invalid_interpolated_expression = invalid interpolated expression
+
+parse_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+ .label = invalid suffix `{$suffix}`
+
+parse_invalid_literal_suffix_on_tuple_index = suffixes on a tuple index are invalid
+ .label = invalid suffix `{$suffix}`
+ .tuple_exception_line_1 = `{$suffix}` is *temporarily* accepted on tuple index fields as it was incorrectly accepted on stable for a few releases
+ .tuple_exception_line_2 = on proc macros, you'll want to use `syn::Index::from` or `proc_macro::Literal::*_unsuffixed` for code that will desugar to tuple field access
+ .tuple_exception_line_3 = see issue #60210 <https://github.com/rust-lang/rust/issues/60210> for more information
+
+parse_invalid_logical_operator = `{$incorrect}` is not a logical operator
+ .note = unlike in e.g., Python and PHP, `&&` and `||` are used for logical operators
+ .use_amp_amp_for_conjunction = use `&&` to perform logical conjunction
+ .use_pipe_pipe_for_disjunction = use `||` to perform logical disjunction
+
+parse_invalid_meta_item = expected unsuffixed literal or identifier, found `{$token}`
+
+parse_invalid_num_literal_base_prefix = invalid base prefix for number literal
+ .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+ .suggestion = try making the prefix lowercase
+
+parse_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+ .label = invalid suffix `{$suffix}`
+ .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+
+parse_invalid_unicode_escape = invalid unicode character escape
+ .label = invalid escape
+ .help = unicode escape must {$surrogate ->
+ [true] not be a surrogate
+ *[false] be at most 10FFFF
}
- .suggestion = {$num_extra_brackets ->
- [one] remove extra angle bracket
- *[other] remove extra angle brackets
- }
-parse_generic_parameters_without_angle_brackets = generic parameters without surrounding angle brackets
- .suggestion = surround the type parameters with angle brackets
+parse_invalid_variable_declaration =
+ invalid variable declaration
-parse_comparison_operators_cannot_be_chained = comparison operators cannot be chained
- .sugg_parentheses_for_function_args = or use `(...)` if you meant to specify fn arguments
- .sugg_split_comparison = split the comparison into two
- .sugg_parenthesize = parenthesize the comparison
-parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
+parse_kw_bad_case = keyword `{$kw}` is written in the wrong case
+ .suggestion = write it in the correct case
-parse_question_mark_in_type = invalid `?` in type
- .label = `?` is only allowed on expressions, not types
- .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
+parse_label_inner_attr_does_not_annotate_this = the inner attribute doesn't annotate this {$item}
+parse_label_unexpected_token = unexpected token
-parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
- .suggestion = remove parentheses in `for` loop
+parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
-parse_doc_comment_on_param_type = documentation comments cannot be applied to a function parameter's type
- .label = doc comments are not allowed here
+parse_labeled_loop_in_break = parentheses are required around this expression to avoid confusion with a labeled break expression
-parse_attribute_on_param_type = attributes cannot be applied to a function parameter's type
- .label = attributes are not allowed here
+parse_leading_plus_not_supported = leading `+` is not supported
+ .label = unexpected `+`
+ .suggestion_remove_plus = try removing the `+`
-parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
- .suggestion = give this argument a name or use an underscore to ignore it
+parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
+parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
-parse_self_param_not_first = unexpected `self` parameter in function
- .label = must be the first parameter of an associated function
+parse_left_arrow_operator = unexpected token: `<-`
+ .suggestion = if you meant to write a comparison against a negative value, add a space in between `<` and `-`
-parse_const_generic_without_braces = expressions must be enclosed in braces to be used as const generic arguments
- .suggestion = enclose the `const` expression in braces
+parse_lifetime_after_mut = lifetime must precede `mut`
+ .suggestion = place the lifetime before `mut`
-parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
- .label = expected a `const` expression, not a parameter declaration
- .suggestion = `const` parameters must be declared for the `impl`
+parse_lifetime_in_borrow_expression = borrow expressions cannot be annotated with lifetimes
+ .suggestion = remove the lifetime annotation
+ .label = annotated with lifetime here
-parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
- .suggestion = the `const` keyword is only needed in the definition of the type
+parse_lone_slash = invalid trailing slash in literal
+ .label = {parse_lone_slash}
-parse_async_move_order_incorrect = the order of `move` and `async` is incorrect
- .suggestion = try switching the order
+parse_loop_else = `{$loop_kind}...else` loops are not supported
+ .note = consider moving this `else` clause to a separate `if` statement and use a `bool` variable to control if it should run
+ .loop_keyword = `else` is attached to this loop
-parse_double_colon_in_bound = expected `:` followed by trait or lifetime
- .suggestion = use single colon
+parse_macro_invocation_visibility = can't qualify macro invocation with `pub`
+ .suggestion = remove the visibility
+ .help = try adjusting the macro to put `{$vis}` inside the invocation
-parse_fn_ptr_with_generics = function pointer types may not have generic parameters
- .suggestion = consider moving the lifetime {$arity ->
- [one] parameter
- *[other] parameters
- } to {$for_param_list_exists ->
- [true] the
- *[false] a
- } `for` parameter list
+parse_macro_invocation_with_qualified_path = macros cannot use qualified paths
-parse_invalid_identifier_with_leading_number = identifiers cannot start with a number
+parse_macro_name_remove_bang = macro names aren't followed by a `!`
+ .suggestion = remove the `!`
+
+parse_macro_rules_missing_bang = expected `!` after `macro_rules`
+ .suggestion = add a `!`
+
+parse_macro_rules_visibility = can't qualify macro_rules invocation with `{$vis}`
+ .suggestion = try exporting the macro
+
+parse_malformed_cfg_attr = malformed `cfg_attr` attribute input
+ .suggestion = missing condition and attribute
+ .note = for more information, visit <https://doc.rust-lang.org/reference/conditional-compilation.html#the-cfg_attr-attribute>
+
+parse_malformed_loop_label = malformed loop label
+ .suggestion = use the correct loop label format
+
+parse_match_arm_body_without_braces = `match` arm body without braces
+ .label_statements = {$num_statements ->
+ [one] this statement is not surrounded by a body
+ *[other] these statements are not surrounded by a body
+ }
+ .label_arrow = while parsing the `match` arm starting here
+ .suggestion_add_braces = surround the {$num_statements ->
+ [one] statement
+ *[other] statements
+ } with a body
+ .suggestion_use_comma_not_semicolon = replace `;` with `,` to end a `match` arm expression
parse_maybe_fn_typo_with_impl = you might have meant to write `impl` instead of `fn`
.suggestion = replace `fn` with `impl` here
-parse_expected_fn_path_found_fn_keyword = expected identifier, found keyword `fn`
- .suggestion = use `Fn` to refer to the trait
+parse_maybe_recover_from_bad_qpath_stage_2 =
+ missing angle brackets in associated item path
+ .suggestion = try: `{$ty}`
-parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
- .label = unexpected where clause
- .name_label = while parsing this tuple struct
- .body_label = the struct body
- .suggestion = move the body before the where clause
+parse_maybe_recover_from_bad_type_plus =
+ expected a path on the left-hand side of `+`, not `{$ty}`
-parse_async_fn_in_2015 = `async fn` is not permitted in Rust 2015
- .label = to use `async fn`, switch to Rust 2018 or later
+parse_maybe_report_ambiguous_plus =
+ ambiguous `+` in a type
+ .suggestion = use parentheses to disambiguate
-parse_async_block_in_2015 = `async` blocks are only allowed in Rust 2018 or later
+parse_meta_bad_delim = wrong meta list delimiters
+parse_meta_bad_delim_suggestion = the delimiters should be `(` and `)`
-parse_self_argument_pointer = cannot pass `self` by raw pointer
- .label = cannot pass `self` by raw pointer
+parse_mismatched_closing_delimiter = mismatched closing delimiter: `{$delimiter}`
+ .label_unmatched = mismatched closing delimiter
+ .label_opening_candidate = closing delimiter possibly meant for this
+ .label_unclosed = unclosed delimiter
-parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
- .label = the visibility
- .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+parse_missing_comma_after_match_arm = expected `,` following `match` arm
+ .suggestion = missing a comma here to end this `match` arm
-parse_default_not_followed_by_item = `default` is not followed by an item
- .label = the `default` qualifier
- .note = only `fn`, `const`, `type`, or `impl` items may be prefixed by `default`
+parse_missing_const_type = missing type for `{$kind}` item
+ .suggestion = provide a type for the item
-parse_missing_struct_for_struct_definition = missing `struct` for struct definition
- .suggestion = add `struct` here to parse `{$ident}` as a public struct
+parse_missing_expression_in_for_loop = missing expression to iterate on in `for` loop
+ .suggestion = try adding an expression to the `for` loop
parse_missing_fn_for_function_definition = missing `fn` for function definition
.suggestion = add `fn` here to parse `{$ident}` as a public function
@@ -451,269 +527,275 @@ parse_missing_fn_for_function_definition = missing `fn` for function definition
parse_missing_fn_for_method_definition = missing `fn` for method definition
.suggestion = add `fn` here to parse `{$ident}` as a public method
-parse_ambiguous_missing_keyword_for_item_definition = missing `fn` or `struct` for function or struct definition
- .suggestion = if you meant to call a macro, try
- .help = if you meant to call a macro, remove the `pub` and add a trailing `!` after the identifier
+parse_missing_for_in_trait_impl = missing `for` in a trait impl
+ .suggestion = add `for` here
+
+parse_missing_in_in_for_loop = missing `in` in `for` loop
+ .use_in_not_of = try using `in` here instead
+ .add_in = try adding `in` here
+
+parse_missing_let_before_mut = missing keyword
+parse_missing_plus_in_bounds = expected `+` between lifetime and {$sym}
+ .suggestion = add `+`
+
+parse_missing_semicolon_before_array = expected `;`, found `[`
+ .suggestion = consider adding `;` here
+
+parse_missing_struct_for_struct_definition = missing `struct` for struct definition
+ .suggestion = add `struct` here to parse `{$ident}` as a public struct
parse_missing_trait_in_trait_impl = missing trait in a trait impl
.suggestion_add_trait = add a trait here
.suggestion_remove_for = for an inherent impl, drop this `for`
-parse_missing_for_in_trait_impl = missing `for` in a trait impl
- .suggestion = add `for` here
+parse_modifier_lifetime = `{$sigil}` may only modify trait bounds, not lifetime bounds
+ .suggestion = remove the `{$sigil}`
-parse_expected_trait_in_trait_impl_found_type = expected a trait, found type
+parse_more_than_one_char = character literal may only contain one codepoint
+ .followed_by = this `{$chr}` is followed by the combining {$len ->
+ [one] mark
+ *[other] marks
+ } `{$escaped_marks}`
+ .non_printing = there are non-printing characters, the full sequence is `{$escaped}`
+ .consider_normalized = consider using the normalized form `{$ch}` of this character
+ .remove_non = consider removing the non-printing characters
+ .use_double_quotes = if you meant to write a {$is_byte ->
+ [true] byte string
+ *[false] `str`
+ } literal, use double quotes
-parse_non_item_in_item_list = non-item in item list
- .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
- .label_list_start = item list starts here
- .label_non_item = non-item starts here
- .label_list_end = item list ends here
- .suggestion_remove_semicolon = consider removing this semicolon
+parse_multiple_skipped_lines = multiple lines skipped by escaped newline
+ .label = skipping everything up to and including this point
-parse_bounds_not_allowed_on_trait_aliases = bounds are not allowed on trait aliases
+parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
+ .label = previous `where` clause starts here
+ .suggestion = consider joining the two `where` clauses into one
-parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
-parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
+parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
+ .suggestion = add `mut` to each binding
+parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
+ .suggestion = remove the `mut` prefix
+parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
-parse_associated_static_item_not_allowed = associated `static` items are not allowed
+parse_nested_adt = `{$kw_str}` definition cannot be nested inside `{$keyword}`
+ .suggestion = consider creating a new `{$kw_str}` definition instead of nesting
-parse_extern_crate_name_with_dashes = crate name using dashes are not valid in `extern crate` statements
- .label = dash-separated idents are not valid
- .suggestion = if the original crate name uses dashes you need to use underscores in the code
+parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
-parse_extern_item_cannot_be_const = extern items cannot be `const`
- .suggestion = try using a static value
- .note = for more information, visit https://doc.rust-lang.org/std/keyword.extern.html
+parse_no_brace_unicode_escape = incorrect unicode escape sequence
+ .label = {parse_no_brace_unicode_escape}
+ .use_braces = format of unicode escape sequences uses braces
+ .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
-parse_const_global_cannot_be_mutable = const globals cannot be mutable
- .label = cannot be mutable
- .suggestion = you might want to declare a static instead
+parse_no_digits_literal = no valid digits found for number
-parse_missing_const_type = missing type for `{$kind}` item
- .suggestion = provide a type for the item
+parse_non_item_in_item_list = non-item in item list
+ .suggestion_use_const_not_let = consider using `const` instead of `let` for associated const
+ .label_list_start = item list starts here
+ .label_non_item = non-item starts here
+ .label_list_end = item list ends here
+ .suggestion_remove_semicolon = consider removing this semicolon
-parse_enum_struct_mutually_exclusive = `enum` and `struct` are mutually exclusive
- .suggestion = replace `enum struct` with
+parse_non_string_abi_literal = non-string ABI literal
+ .suggestion = specify the ABI with a string literal
-parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
-parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
-parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
-parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
-parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
+parse_nonterminal_expected_ident = expected ident, found `{$token}`
+parse_nonterminal_expected_item_keyword = expected an item keyword
+parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
-parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
- .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
+parse_nonterminal_expected_statement = expected a statement
+parse_not_supported = not supported
-parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
- .label = lifetime parameters cannot have default values
+parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
-parse_multiple_where_clauses = cannot define duplicate `where` clauses on an item
- .label = previous `where` clause starts here
- .suggestion = consider joining the two `where` clauses into one
+parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
-parse_nonterminal_expected_item_keyword = expected an item keyword
-parse_nonterminal_expected_statement = expected a statement
-parse_nonterminal_expected_ident = expected ident, found `{$token}`
-parse_nonterminal_expected_lifetime = expected a lifetime, found `{$token}`
+parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
-parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_octal_float_literal_not_supported = octal float literal is not supported
parse_or_pattern_not_allowed_in_fn_parameters = top-level or-patterns are not allowed in function parameters
-parse_sugg_remove_leading_vert_in_pattern = remove the `|`
-parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
+parse_or_pattern_not_allowed_in_let_binding = top-level or-patterns are not allowed in `let` bindings
+parse_out_of_range_hex_escape = out of range hex escape
+ .label = must be a character in the range [\x00-\x7f]
-parse_note_pattern_alternatives_use_single_vert = alternatives in or-patterns are separated with `|`, not `||`
+parse_outer_attr_explanation = outer attributes, like `#[test]`, annotate the item following them
-parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
- .suggestion = remove the `||`
+parse_outer_attribute_not_allowed_on_if_else = outer attributes are not allowed on `if` and `else` branches
+ .branch_label = the attributes are attached to this branch
+ .ctx_label = the branch belongs to this `{$ctx}`
+ .suggestion = remove the attributes
-parse_label_while_parsing_or_pattern_here = while parsing this or-pattern starting here
+parse_overlong_unicode_escape = overlong unicode escape
+ .label = must have at most 6 hex digits
-parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
- .suggestion = use a single `|` to separate multiple alternative patterns
+parse_parentheses_with_struct_fields = invalid `struct` delimiters or `fn` call arguments
+ .suggestion_braces_for_struct = if `{$type}` is a struct, use braces as delimiters
+ .suggestion_no_fields_for_fn = if `{$type}` is a function, use the arguments directly
-parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
- .suggestion = remove the `{$token}`
+parse_parenthesized_lifetime = parenthesized lifetime bounds are not supported
+ .suggestion = remove the parentheses
-parse_dotdotdot_rest_pattern = unexpected `...`
- .label = not a valid pattern
- .suggestion = for a rest pattern, use `..` instead of `...`
+parse_path_single_colon = path separator must be a double colon
+ .suggestion = use a double colon instead
+
+parse_pattern_method_param_without_body = patterns aren't allowed in methods without bodies
+ .suggestion = give this argument a name or use an underscore to ignore it
parse_pattern_on_wrong_side_of_at = pattern on wrong side of `@`
.label_pattern = pattern on the left, should be on the right
.label_binding = binding on the right, should be on the left
.suggestion = switch the order
-parse_expected_binding_left_of_at = left-hand side of `@` must be a binding
- .label_lhs = interpreted as a pattern, not a binding
- .label_rhs = also a pattern
- .note = bindings are `x`, `mut x`, `ref x`, and `ref mut x`
-
-parse_ambiguous_range_pattern = the range pattern here has ambiguous interpretation
- .suggestion = add parentheses to clarify the precedence
+parse_question_mark_in_type = invalid `?` in type
+ .label = `?` is only allowed on expressions, not types
+ .suggestion = if you meant to express that the type might not contain a value, use the `Option` wrapper type
-parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
- .suggestion = remove the lifetime
+parse_recover_import_as_use = expected item, found {$token_name}
+ .suggestion = items are imported using the `use` keyword
parse_ref_mut_order_incorrect = the order of `mut` and `ref` is incorrect
.suggestion = try switching the order
-parse_mut_on_nested_ident_pattern = `mut` must be attached to each individual binding
- .suggestion = add `mut` to each binding
-parse_mut_on_non_ident_pattern = `mut` must be followed by a named binding
- .suggestion = remove the `mut` prefix
-parse_note_mut_pattern_usage = `mut` may be followed by `variable` and `variable @ pattern`
+parse_remove_let = expected pattern, found `let`
+ .suggestion = remove the unnecessary `let` keyword
parse_repeated_mut_in_pattern = `mut` on a binding may not be repeated
.suggestion = remove the additional `mut`s
-parse_dot_dot_dot_range_to_pattern_not_allowed = range-to patterns with `...` are not allowed
- .suggestion = use `..=` instead
+parse_require_colon_after_labeled_expression = labeled expression must be followed by `:`
+ .note = labels are used before loops and blocks, allowing e.g., `break 'label` to them
+ .label = the label
+ .suggestion = add `:` after the label
-parse_enum_pattern_instead_of_identifier = expected identifier, found enum pattern
+parse_return_types_use_thin_arrow = return types are denoted using `->`
+ .suggestion = use `->` instead
-parse_dot_dot_dot_for_remaining_fields = expected field pattern, found `{$token_str}`
- .suggestion = to omit remaining fields, use `..`
+parse_self_argument_pointer = cannot pass `self` by raw pointer
+ .label = cannot pass `self` by raw pointer
-parse_expected_comma_after_pattern_field = expected `,`
+parse_self_param_not_first = unexpected `self` parameter in function
+ .label = must be the first parameter of an associated function
-parse_return_types_use_thin_arrow = return types are denoted using `->`
- .suggestion = use `->` instead
+parse_shift_interpreted_as_generic =
+ `<<` is interpreted as a start of generic arguments for `{$type}`, not a shift
+ .label_args = interpreted as generic arguments
+ .label_comparison = not interpreted as shift
+ .suggestion = try shifting the cast value
-parse_need_plus_after_trait_object_lifetime = lifetime in trait object type must be followed by `+`
+parse_single_colon_import_path = expected `::`, found `:`
+ .suggestion = use double colon
+ .note = import paths are delimited using `::`
-parse_expected_mut_or_const_in_raw_pointer_type = expected `mut` or `const` keyword in raw pointer type
- .suggestion = add `mut` or `const` here
+parse_single_colon_struct_type = found single colon in a struct field type path
+ .suggestion = write a path separator here
-parse_lifetime_after_mut = lifetime must precede `mut`
- .suggestion = place the lifetime before `mut`
+parse_struct_literal_body_without_path =
+ struct literal body without path
+ .suggestion = you might have forgotten to add the struct literal inside the block
-parse_dyn_after_mut = `mut` must precede `dyn`
- .suggestion = place `mut` before `dyn`
+parse_struct_literal_needing_parens =
+ invalid struct literal
+ .suggestion = you might need to surround the struct literal in parentheses
-parse_fn_pointer_cannot_be_const = an `fn` pointer type cannot be `const`
- .label = `const` because of this
- .suggestion = remove the `const` qualifier
+parse_struct_literal_not_allowed_here = struct literals are not allowed here
+ .suggestion = surround the struct literal with parentheses
-parse_fn_pointer_cannot_be_async = an `fn` pointer type cannot be `async`
- .label = `async` because of this
- .suggestion = remove the `async` qualifier
+parse_suffixed_literal_in_attribute = suffixed literals are not allowed in attributes
+ .help = instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.)
-parse_nested_c_variadic_type = C-variadic type `...` may not be nested inside another type
+parse_sugg_add_let_for_stmt = you might have meant to introduce a new binding
-parse_invalid_dyn_keyword = invalid `dyn` keyword
- .help = `dyn` is only needed at the start of a trait `+`-separated list
- .suggestion = remove this keyword
+parse_sugg_add_semi = add `;` here
+parse_sugg_change_inner_attr_to_outer = to annotate the {$item}, change the attribute from inner to outer style
-parse_negative_bounds_not_supported = negative bounds are not supported
- .label = negative bounds are not supported
- .suggestion = {$num_bounds ->
- [one] remove the bound
- *[other] remove the bounds
- }
+parse_sugg_change_this_to_semi = change this to `;`
+parse_sugg_escape_identifier = escape `{$ident_name}` to use it as an identifier
-parse_help_set_edition_cargo = set `edition = "{$edition}"` in `Cargo.toml`
-parse_help_set_edition_standalone = pass `--edition {$edition}` to `rustc`
-parse_note_edition_guide = for more on editions, read https://doc.rust-lang.org/edition-guide
+parse_sugg_remove_comma = remove this comma
+parse_sugg_remove_leading_vert_in_pattern = remove the `|`
+parse_sugg_turbofish_syntax = use `::<...>` instead of `<...>` to specify lifetime, type, or const arguments
-parse_unexpected_token_after_dot = unexpected token: `{$actual}`
+parse_sugg_wrap_expression_in_parentheses = wrap the expression in parentheses
-parse_cannot_be_raw_ident = `{$ident}` cannot be a raw identifier
+parse_sugg_wrap_pattern_in_parens = wrap the pattern in parentheses
-parse_cr_doc_comment = bare CR not allowed in {$block ->
- [true] block doc-comment
- *[false] doc-comment
-}
+parse_switch_mut_let_order =
+ switch the order of `mut` and `let`
+parse_tilde_const_lifetime = `~const` may only modify trait bounds, not lifetime bounds
-parse_no_digits_literal = no valid digits found for number
+parse_tilde_is_not_unary_operator = `~` cannot be used as a unary operator
+ .suggestion = use `!` to perform bitwise not
-parse_invalid_digit_literal = invalid digit for a base {$base} literal
+parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
-parse_empty_exponent_float = expected at least one digit in exponent
+parse_too_short_hex_escape = numeric character escape is too short
-parse_float_literal_unsupported_base = {$base} float literal is not supported
+parse_trailing_vert_not_allowed = a trailing `|` is not allowed in an or-pattern
+ .suggestion = remove the `{$token}`
-parse_more_than_one_char = character literal may only contain one codepoint
- .followed_by = this `{$chr}` is followed by the combining {$len ->
- [one] mark
- *[other] marks
- } `{$escaped_marks}`
- .non_printing = there are non-printing characters, the full sequence is `{$escaped}`
- .consider_normalized = consider using the normalized form `{$ch}` of this character
- .remove_non = consider removing the non-printing characters
- .use_double_quotes = if you meant to write a {$is_byte ->
- [true] byte string
- *[false] `str`
- } literal, use double quotes
+parse_trait_alias_cannot_be_auto = trait aliases cannot be `auto`
+parse_trait_alias_cannot_be_unsafe = trait aliases cannot be `unsafe`
-parse_no_brace_unicode_escape = incorrect unicode escape sequence
- .label = {parse_no_brace_unicode_escape}
- .use_braces = format of unicode escape sequences uses braces
- .format_of_unicode = format of unicode escape sequences is `\u{"{...}"}`
+parse_type_ascription_removed =
+ if you meant to annotate an expression with a type, the type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>
-parse_invalid_unicode_escape = invalid unicode character escape
- .label = invalid escape
- .help = unicode escape must {$surrogate ->
- [true] not be a surrogate
- *[false] be at most 10FFFF
- }
+parse_unclosed_unicode_escape = unterminated unicode escape
+ .label = missing a closing `{"}"}`
+ .terminate = terminate the unicode escape
-parse_escape_only_char = {$byte ->
- [true] byte
- *[false] character
- } constant must be escaped: `{$escaped_msg}`
- .escape = escape the character
+parse_underscore_literal_suffix = underscore literal suffix is not allowed
-parse_bare_cr = {$double_quotes ->
- [true] bare CR not allowed in string, use `\r` instead
- *[false] character constant must be escaped: `\r`
- }
- .escape = escape the character
+parse_unexpected_const_in_generic_param = expected lifetime, type, or constant, found keyword `const`
+ .suggestion = the `const` keyword is only needed in the definition of the type
-parse_bare_cr_in_raw_string = bare CR not allowed in raw string
+parse_unexpected_const_param_declaration = unexpected `const` parameter declaration
+ .label = expected a `const` expression, not a parameter declaration
+ .suggestion = `const` parameters must be declared for the `impl`
-parse_too_short_hex_escape = numeric character escape is too short
+parse_unexpected_default_value_for_lifetime_in_generic_parameters = unexpected default lifetime parameter
+ .label = lifetime parameters cannot have default values
-parse_invalid_char_in_escape = {parse_invalid_char_in_escape_msg}: `{$ch}`
- .label = {parse_invalid_char_in_escape_msg}
+parse_unexpected_if_with_if = unexpected `if` in the condition expression
+ .suggestion = remove the `if`
-parse_invalid_char_in_escape_msg = invalid character in {$is_hex ->
- [true] numeric character
- *[false] unicode
- } escape
+parse_unexpected_lifetime_in_pattern = unexpected lifetime `{$symbol}` in pattern
+ .suggestion = remove the lifetime
-parse_out_of_range_hex_escape = out of range hex escape
- .label = must be a character in the range [\x00-\x7f]
+parse_unexpected_parentheses_in_for_head = unexpected parentheses surrounding `for` loop head
+ .suggestion = remove parentheses in `for` loop
-parse_leading_underscore_unicode_escape = {parse_leading_underscore_unicode_escape_label}: `_`
-parse_leading_underscore_unicode_escape_label = invalid start of unicode escape
+parse_unexpected_self_in_generic_parameters = unexpected keyword `Self` in generic parameters
+ .note = you cannot use `Self` as a generic parameter because it is reserved for associated items
-parse_overlong_unicode_escape = overlong unicode escape
- .label = must have at most 6 hex digits
+parse_unexpected_token_after_dot = unexpected token: `{$actual}`
-parse_unclosed_unicode_escape = unterminated unicode escape
- .label = missing a closing `{"}"}`
- .terminate = terminate the unicode escape
+parse_unexpected_token_after_label = expected `while`, `for`, `loop` or `{"{"}` after a label
+ .suggestion_remove_label = consider removing the label
+ .suggestion_enclose_in_block = consider enclosing expression in a block
-parse_unicode_escape_in_byte = unicode escape in byte string
- .label = {parse_unicode_escape_in_byte}
- .help = unicode escape sequences cannot be used as a byte or in a byte string
+parse_unexpected_token_after_not = unexpected {$negated_desc} after identifier
+parse_unexpected_token_after_not_bitwise = use `!` to perform bitwise not
+parse_unexpected_token_after_not_default = use `!` to perform logical negation or bitwise not
-parse_empty_unicode_escape = empty unicode escape
- .label = this escape must have at least 1 hex digit
+parse_unexpected_token_after_not_logical = use `!` to perform logical negation
+parse_unexpected_token_after_struct_name = expected `where`, `{"{"}`, `(`, or `;` after struct name
+parse_unexpected_token_after_struct_name_found_doc_comment = expected `where`, `{"{"}`, `(`, or `;` after struct name, found doc comment `{$token}`
+parse_unexpected_token_after_struct_name_found_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found keyword `{$token}`
+parse_unexpected_token_after_struct_name_found_other = expected `where`, `{"{"}`, `(`, or `;` after struct name, found `{$token}`
-parse_zero_chars = empty character literal
- .label = {parse_zero_chars}
+parse_unexpected_token_after_struct_name_found_reserved_identifier = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved identifier `{$token}`
+parse_unexpected_token_after_struct_name_found_reserved_keyword = expected `where`, `{"{"}`, `(`, or `;` after struct name, found reserved keyword `{$token}`
+parse_unexpected_vert_vert_before_function_parameter = unexpected `||` before function parameter
+ .suggestion = remove the `||`
-parse_lone_slash = invalid trailing slash in literal
- .label = {parse_lone_slash}
+parse_unexpected_vert_vert_in_pattern = unexpected token `||` in pattern
+ .suggestion = use a single `|` to separate multiple alternative patterns
-parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
- .label = {parse_unskipped_whitespace}
+parse_unicode_escape_in_byte = unicode escape in byte string
+ .label = {parse_unicode_escape_in_byte}
+ .help = unicode escape sequences cannot be used as a byte or in a byte string
-parse_multiple_skipped_lines = multiple lines skipped by escaped newline
- .label = skipping everything up to and including this point
+parse_unknown_builtin_construct = unknown `builtin #` construct `{$name}`
parse_unknown_prefix = prefix `{$prefix}` is unknown
.label = unknown prefix
@@ -721,8 +803,6 @@ parse_unknown_prefix = prefix `{$prefix}` is unknown
.suggestion_br = use `br` for a raw byte string
.suggestion_whitespace = consider inserting whitespace here
-parse_too_many_hashes = too many `#` symbols: raw strings may be delimited by up to 255 `#` symbols, but found {$num}
-
parse_unknown_start_of_token = unknown start of token: {$escaped}
.sugg_quotes = Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '{$ascii_str}' ({$ascii_name}), but are not
.sugg_other = Unicode character '{$ch}' ({$u_name}) looks like '{$ascii_str}' ({$ascii_name}), but it is not
@@ -732,13 +812,48 @@ parse_unknown_start_of_token = unknown start of token: {$escaped}
*[other] {$repeats} more times
}
-parse_box_syntax_removed = `box_syntax` has been removed
- .suggestion = use `Box::new()` instead
+parse_unmatched_angle = unmatched angle {$plural ->
+ [true] brackets
+ *[false] bracket
+ }
+ .suggestion = remove extra angle {$plural ->
+ [true] brackets
+ *[false] bracket
+ }
-parse_bad_return_type_notation_output =
- return type not allowed with return type notation
- .suggestion = remove the return type
+parse_unmatched_angle_brackets = {$num_extra_brackets ->
+ [one] unmatched angle bracket
+ *[other] unmatched angle brackets
+ }
+ .suggestion = {$num_extra_brackets ->
+ [one] remove extra angle bracket
+ *[other] remove extra angle brackets
+ }
-parse_bad_return_type_notation_dotdot =
- return type notation uses `()` instead of `(..)` for elided arguments
- .suggestion = remove the `..`
+parse_unskipped_whitespace = whitespace symbol '{$ch}' is not skipped
+ .label = {parse_unskipped_whitespace}
+
+parse_use_empty_block_not_semi = expected { "`{}`" }, found `;`
+ .suggestion = try using { "`{}`" } instead
+
+parse_use_eq_instead = unexpected `==`
+ .suggestion = try using `=` instead
+
+parse_use_let_not_auto = write `let` instead of `auto` to introduce a new variable
+parse_use_let_not_var = write `let` instead of `var` to introduce a new variable
+
+parse_visibility_not_followed_by_item = visibility `{$vis}` is not followed by an item
+ .label = the visibility
+ .help = you likely meant to define an item, e.g., `{$vis} fn foo() {"{}"}`
+
+parse_where_clause_before_tuple_struct_body = where clauses are not allowed before tuple struct bodies
+ .label = unexpected where clause
+ .name_label = while parsing this tuple struct
+ .body_label = the struct body
+ .suggestion = move the body before the where clause
+
+parse_where_generics = generic parameters on `where` clauses are reserved for future use
+ .label = currently unsupported
+
+parse_zero_chars = empty character literal
+ .label = {parse_zero_chars}
diff --git a/compiler/rustc_parse/src/errors.rs b/compiler/rustc_parse/src/errors.rs
index 069217165..84494eab8 100644
--- a/compiler/rustc_parse/src/errors.rs
+++ b/compiler/rustc_parse/src/errors.rs
@@ -907,6 +907,18 @@ pub(crate) struct SuggRemoveComma {
}
#[derive(Subdiagnostic)]
+#[suggestion(
+ parse_sugg_add_let_for_stmt,
+ style = "verbose",
+ applicability = "maybe-incorrect",
+ code = "let "
+)]
+pub(crate) struct SuggAddMissingLetStmt {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Subdiagnostic)]
pub(crate) enum ExpectedIdentifierFound {
#[label(parse_expected_identifier_found_reserved_identifier)]
ReservedIdentifier(#[primary_span] Span),
@@ -1341,6 +1353,28 @@ pub(crate) struct ExpectedFnPathFoundFnKeyword {
}
#[derive(Diagnostic)]
+#[diag(parse_path_single_colon)]
+pub(crate) struct PathSingleColon {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = "::")]
+ pub span: Span,
+
+ #[note(parse_type_ascription_removed)]
+ pub type_ascription: Option<()>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_colon_as_semi)]
+pub(crate) struct ColonAsSemi {
+ #[primary_span]
+ #[suggestion(applicability = "machine-applicable", code = ";")]
+ pub span: Span,
+
+ #[note(parse_type_ascription_removed)]
+ pub type_ascription: Option<()>,
+}
+
+#[derive(Diagnostic)]
#[diag(parse_where_clause_before_tuple_struct_body)]
pub(crate) struct WhereClauseBeforeTupleStructBody {
#[primary_span]
@@ -1486,6 +1520,16 @@ pub(crate) struct ExpectedTraitInTraitImplFoundType {
}
#[derive(Diagnostic)]
+#[diag(parse_extra_impl_keyword_in_trait_impl)]
+pub(crate) struct ExtraImplKeywordInTraitImpl {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ pub extra_impl_kw: Span,
+ #[note]
+ pub impl_trait_span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(parse_bounds_not_allowed_on_trait_aliases)]
pub(crate) struct BoundsNotAllowedOnTraitAliases {
#[primary_span]
@@ -2258,31 +2302,6 @@ pub(crate) struct InvalidDynKeyword {
pub span: Span,
}
-#[derive(Diagnostic)]
-#[diag(parse_negative_bounds_not_supported)]
-pub(crate) struct NegativeBoundsNotSupported {
- #[primary_span]
- pub negative_bounds: Vec<Span>,
- #[label]
- pub last_span: Span,
- #[subdiagnostic]
- pub sub: Option<NegativeBoundsNotSupportedSugg>,
-}
-
-#[derive(Subdiagnostic)]
-#[suggestion(
- parse_suggestion,
- style = "tool-only",
- code = "{fixed}",
- applicability = "machine-applicable"
-)]
-pub(crate) struct NegativeBoundsNotSupportedSugg {
- #[primary_span]
- pub bound_list: Span,
- pub num_bounds: usize,
- pub fixed: String,
-}
-
#[derive(Subdiagnostic)]
pub enum HelpUseLatestEdition {
#[help(parse_help_set_edition_cargo)]
@@ -2332,3 +2351,333 @@ pub(crate) struct BadReturnTypeNotationDotDot {
#[suggestion(code = "", applicability = "maybe-incorrect")]
pub span: Span,
}
+
+#[derive(Diagnostic)]
+#[diag(parse_bad_assoc_type_bounds)]
+pub(crate) struct BadAssocTypeBounds {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_attr_after_generic)]
+pub(crate) struct AttrAfterGeneric {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_attr_without_generics)]
+pub(crate) struct AttrWithoutGenerics {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_where_generics)]
+pub(crate) struct WhereOnGenerics {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_generics_in_path)]
+pub(crate) struct GenericsInPath {
+ #[primary_span]
+ pub span: Vec<Span>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_assoc_lifetime)]
+#[help]
+pub(crate) struct AssocLifetime {
+ #[primary_span]
+ pub span: Span,
+ #[label]
+ pub lifetime: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_tilde_const_lifetime)]
+pub(crate) struct TildeConstLifetime {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_modifier_lifetime)]
+pub(crate) struct ModifierLifetime {
+ #[primary_span]
+ #[suggestion(style = "tool-only", applicability = "maybe-incorrect", code = "")]
+ pub span: Span,
+ pub sigil: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_parenthesized_lifetime)]
+pub(crate) struct ParenthesizedLifetime {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(style = "short", applicability = "machine-applicable", code = "{snippet}")]
+ pub sugg: Option<Span>,
+ pub snippet: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_const_bounds_missing_tilde)]
+pub(crate) struct ConstMissingTilde {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "~", applicability = "machine-applicable")]
+ pub start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_underscore_literal_suffix)]
+pub(crate) struct UnderscoreLiteralSuffix {
+ #[primary_span]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expect_label_found_ident)]
+pub(crate) struct ExpectedLabelFoundIdent {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "'", applicability = "machine-applicable", style = "short")]
+ pub start: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_inappropriate_default)]
+#[note]
+pub(crate) struct InappropriateDefault {
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ pub article: &'static str,
+ pub descr: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_recover_import_as_use)]
+pub(crate) struct RecoverImportAsUse {
+ #[primary_span]
+ #[suggestion(code = "use", applicability = "machine-applicable", style = "short")]
+ pub span: Span,
+ pub token_name: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_single_colon_import_path)]
+#[note]
+pub(crate) struct SingleColonImportPath {
+ #[primary_span]
+ #[suggestion(code = "::", applicability = "machine-applicable", style = "short")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_bad_item_kind)]
+#[help]
+pub(crate) struct BadItemKind {
+ #[primary_span]
+ pub span: Span,
+ pub descr: &'static str,
+ pub ctx: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_single_colon_struct_type)]
+pub(crate) struct SingleColonStructType {
+ #[primary_span]
+ #[suggestion(code = "::", applicability = "maybe-incorrect", style = "verbose")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_equals_struct_default)]
+pub(crate) struct EqualsStructDefault {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_rules_missing_bang)]
+pub(crate) struct MacroRulesMissingBang {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "!", applicability = "machine-applicable", style = "verbose")]
+ pub hi: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_name_remove_bang)]
+pub(crate) struct MacroNameRemoveBang {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_rules_visibility)]
+pub(crate) struct MacroRulesVisibility<'a> {
+ #[primary_span]
+ #[suggestion(code = "#[macro_export]", applicability = "maybe-incorrect")]
+ pub span: Span,
+ pub vis: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_macro_invocation_visibility)]
+#[help]
+pub(crate) struct MacroInvocationVisibility<'a> {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ pub vis: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_nested_adt)]
+pub(crate) struct NestedAdt<'a> {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = "", applicability = "maybe-incorrect")]
+ pub item: Span,
+ pub keyword: &'a str,
+ pub kw_str: Cow<'a, str>,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_function_body_equals_expr)]
+pub(crate) struct FunctionBodyEqualsExpr {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: FunctionBodyEqualsExprSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct FunctionBodyEqualsExprSugg {
+ #[suggestion_part(code = "{{")]
+ pub eq: Span,
+ #[suggestion_part(code = " }}")]
+ pub semi: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_box_not_pat)]
+pub(crate) struct BoxNotPat {
+ #[primary_span]
+ pub span: Span,
+ #[note]
+ pub kw: Span,
+ #[suggestion(code = "r#", applicability = "maybe-incorrect", style = "verbose")]
+ pub lo: Span,
+ pub descr: String,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unmatched_angle)]
+pub(crate) struct UnmatchedAngle {
+ #[primary_span]
+ #[suggestion(code = "", applicability = "machine-applicable")]
+ pub span: Span,
+ pub plural: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_missing_plus_in_bounds)]
+pub(crate) struct MissingPlusBounds {
+ #[primary_span]
+ pub span: Span,
+ #[suggestion(code = " +", applicability = "maybe-incorrect", style = "verbose")]
+ pub hi: Span,
+ pub sym: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_incorrect_braces_trait_bounds)]
+pub(crate) struct IncorrectBracesTraitBounds {
+ #[primary_span]
+ pub span: Vec<Span>,
+ #[subdiagnostic]
+ pub sugg: IncorrectBracesTraitBoundsSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_suggestion, applicability = "machine-applicable")]
+pub(crate) struct IncorrectBracesTraitBoundsSugg {
+ #[suggestion_part(code = " ")]
+ pub l: Span,
+ #[suggestion_part(code = "")]
+ pub r: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_kw_bad_case)]
+pub(crate) struct KwBadCase<'a> {
+ #[primary_span]
+ #[suggestion(code = "{kw}", applicability = "machine-applicable")]
+ pub span: Span,
+ pub kw: &'a str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_meta_bad_delim)]
+pub(crate) struct MetaBadDelim {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: MetaBadDelimSugg,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_cfg_attr_bad_delim)]
+pub(crate) struct CfgAttrBadDelim {
+ #[primary_span]
+ pub span: Span,
+ #[subdiagnostic]
+ pub sugg: MetaBadDelimSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(parse_meta_bad_delim_suggestion, applicability = "machine-applicable")]
+pub(crate) struct MetaBadDelimSugg {
+ #[suggestion_part(code = "(")]
+ pub open: Span,
+ #[suggestion_part(code = ")")]
+ pub close: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_malformed_cfg_attr)]
+#[note]
+pub(crate) struct MalformedCfgAttr {
+ #[primary_span]
+ #[suggestion(code = "{sugg}")]
+ pub span: Span,
+ pub sugg: &'static str,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_unknown_builtin_construct)]
+pub(crate) struct UnknownBuiltinConstruct {
+ #[primary_span]
+ pub span: Span,
+ pub name: Symbol,
+}
+
+#[derive(Diagnostic)]
+#[diag(parse_expected_builtin_ident)]
+pub(crate) struct ExpectedBuiltinIdent {
+ #[primary_span]
+ pub span: Span,
+}
diff --git a/compiler/rustc_parse/src/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs
index 9e856c9f2..c6e6b46e4 100644
--- a/compiler/rustc_parse/src/lexer/mod.rs
+++ b/compiler/rustc_parse/src/lexer/mod.rs
@@ -1,3 +1,5 @@
+use std::ops::Range;
+
use crate::errors;
use crate::lexer::unicode_chars::UNICODE_ARRAY;
use crate::make_unclosed_delims_error;
@@ -6,7 +8,7 @@ use rustc_ast::token::{self, CommentKind, Delimiter, Token, TokenKind};
use rustc_ast::tokenstream::TokenStream;
use rustc_ast::util::unicode::contains_text_flow_control_chars;
use rustc_errors::{error_code, Applicability, Diagnostic, DiagnosticBuilder, StashKey};
-use rustc_lexer::unescape::{self, Mode};
+use rustc_lexer::unescape::{self, EscapeError, Mode};
use rustc_lexer::Cursor;
use rustc_lexer::{Base, DocStyle, RawStrError};
use rustc_session::lint::builtin::{
@@ -67,7 +69,7 @@ pub(crate) fn parse_token_trees<'a>(
match token_trees {
Ok(stream) if unmatched_delims.is_empty() => Ok(stream),
_ => {
- // Return error if there are unmatched delimiters or unclosng delimiters.
+ // Return error if there are unmatched delimiters or unclosed delimiters.
// We emit delimiter mismatch errors first, then emit the unclosing delimiter mismatch
// because the delimiter mismatch is more likely to be the root cause of error
@@ -204,16 +206,15 @@ impl<'a> StringReader<'a> {
rustc_lexer::TokenKind::Literal { kind, suffix_start } => {
let suffix_start = start + BytePos(suffix_start);
let (kind, symbol) = self.cook_lexer_literal(start, suffix_start, kind);
+ if let token::LitKind::CStr | token::LitKind::CStrRaw(_) = kind {
+ self.sess.gated_spans.gate(sym::c_str_literals, self.mk_sp(start, self.pos));
+ }
let suffix = if suffix_start < self.pos {
let string = self.str_from(suffix_start);
if string == "_" {
self.sess
.span_diagnostic
- .struct_span_err(
- self.mk_sp(suffix_start, self.pos),
- "underscore literal suffix is not allowed",
- )
- .emit();
+ .emit_err(errors::UnderscoreLiteralSuffix { span: self.mk_sp(suffix_start, self.pos) });
None
} else {
Some(Symbol::intern(string))
@@ -325,7 +326,7 @@ impl<'a> StringReader<'a> {
) -> DiagnosticBuilder<'a, !> {
self.sess
.span_diagnostic
- .struct_span_fatal(self.mk_sp(from_pos, to_pos), &format!("{}: {}", m, escaped_char(c)))
+ .struct_span_fatal(self.mk_sp(from_pos, to_pos), format!("{}: {}", m, escaped_char(c)))
}
/// Detect usages of Unicode codepoints changing the direction of the text on screen and loudly
@@ -419,6 +420,16 @@ impl<'a> StringReader<'a> {
}
self.cook_quoted(token::ByteStr, Mode::ByteStr, start, end, 2, 1) // b" "
}
+ rustc_lexer::LiteralKind::CStr { terminated } => {
+ if !terminated {
+ self.sess.span_diagnostic.span_fatal_with_code(
+ self.mk_sp(start + BytePos(1), end),
+ "unterminated C string",
+ error_code!(E0767),
+ )
+ }
+ self.cook_c_string(token::CStr, Mode::CStr, start, end, 2, 1) // c" "
+ }
rustc_lexer::LiteralKind::RawStr { n_hashes } => {
if let Some(n_hashes) = n_hashes {
let n = u32::from(n_hashes);
@@ -437,6 +448,15 @@ impl<'a> StringReader<'a> {
self.report_raw_str_error(start, 2);
}
}
+ rustc_lexer::LiteralKind::RawCStr { n_hashes } => {
+ if let Some(n_hashes) = n_hashes {
+ let n = u32::from(n_hashes);
+ let kind = token::CStrRaw(n_hashes);
+ self.cook_c_string(kind, Mode::RawCStr, start, end, 3 + n, 1 + n) // cr##" "##
+ } else {
+ self.report_raw_str_error(start, 2);
+ }
+ }
rustc_lexer::LiteralKind::Int { base, empty_int } => {
if empty_int {
let span = self.mk_sp(start, end);
@@ -546,7 +566,7 @@ impl<'a> StringReader<'a> {
err.span_label(self.mk_sp(start, start), "unterminated raw string");
if n_hashes > 0 {
- err.note(&format!(
+ err.note(format!(
"this raw string should be terminated with `\"{}`",
"#".repeat(n_hashes as usize)
));
@@ -642,7 +662,7 @@ impl<'a> StringReader<'a> {
&RUST_2021_PREFIXES_INCOMPATIBLE_SYNTAX,
prefix_span,
ast::CRATE_NODE_ID,
- &format!("prefix `{prefix}` is unknown"),
+ format!("prefix `{prefix}` is unknown"),
BuiltinLintDiagnostics::ReservedPrefix(prefix_span),
);
}
@@ -652,7 +672,7 @@ impl<'a> StringReader<'a> {
self.sess.emit_fatal(errors::TooManyHashes { span: self.mk_sp(start, self.pos), num });
}
- fn cook_quoted(
+ fn cook_common(
&self,
kind: token::LitKind,
mode: Mode,
@@ -660,12 +680,13 @@ impl<'a> StringReader<'a> {
end: BytePos,
prefix_len: u32,
postfix_len: u32,
+ unescape: fn(&str, Mode, &mut dyn FnMut(Range<usize>, Result<(), EscapeError>)),
) -> (token::LitKind, Symbol) {
let mut has_fatal_err = false;
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| {
+ unescape(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(start, end);
@@ -696,6 +717,38 @@ impl<'a> StringReader<'a> {
(token::Err, self.symbol_from_to(start, end))
}
}
+
+ fn cook_quoted(
+ &self,
+ kind: token::LitKind,
+ mode: Mode,
+ start: BytePos,
+ end: BytePos,
+ prefix_len: u32,
+ postfix_len: u32,
+ ) -> (token::LitKind, Symbol) {
+ self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+ unescape::unescape_literal(src, mode, &mut |span, result| {
+ callback(span, result.map(drop))
+ })
+ })
+ }
+
+ fn cook_c_string(
+ &self,
+ kind: token::LitKind,
+ mode: Mode,
+ start: BytePos,
+ end: BytePos,
+ prefix_len: u32,
+ postfix_len: u32,
+ ) -> (token::LitKind, Symbol) {
+ self.cook_common(kind, mode, start, end, prefix_len, postfix_len, |src, mode, callback| {
+ unescape::unescape_c_string(src, mode, &mut |span, result| {
+ callback(span, result.map(drop))
+ })
+ })
+ }
}
pub fn nfc_normalize(string: &str) -> Symbol {
diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs
index 7c2c08951..318a29985 100644
--- a/compiler/rustc_parse/src/lexer/tokentrees.rs
+++ b/compiler/rustc_parse/src/lexer/tokentrees.rs
@@ -199,8 +199,7 @@ impl<'a> TokenTreesReader<'a> {
// matching opening delimiter).
let token_str = token_to_string(&self.token);
let msg = format!("unexpected closing delimiter: `{}`", token_str);
- let mut err =
- self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, &msg);
+ let mut err = self.string_reader.sess.span_diagnostic.struct_span_err(self.token.span, msg);
report_suspicious_mismatch_block(
&mut err,
diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
index 0d12ec608..eb9625f92 100644
--- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
+++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs
@@ -78,8 +78,7 @@ pub(crate) fn emit_unescape_error(
}
};
let sugg = sugg.unwrap_or_else(|| {
- let is_byte = mode.is_byte();
- let prefix = if is_byte { "b" } else { "" };
+ let prefix = mode.prefix_noraw();
let mut escaped = String::with_capacity(lit.len());
let mut chrs = lit.chars().peekable();
while let Some(first) = chrs.next() {
@@ -97,7 +96,11 @@ pub(crate) fn emit_unescape_error(
};
}
let sugg = format!("{prefix}\"{escaped}\"");
- MoreThanOneCharSugg::Quotes { span: span_with_quotes, is_byte, sugg }
+ MoreThanOneCharSugg::Quotes {
+ span: span_with_quotes,
+ is_byte: mode == Mode::Byte,
+ sugg,
+ }
});
handler.emit_err(UnescapeError::MoreThanOneChar {
span: span_with_quotes,
@@ -112,7 +115,7 @@ pub(crate) fn emit_unescape_error(
char_span,
escaped_sugg: c.escape_default().to_string(),
escaped_msg: escaped_char(c),
- byte: mode.is_byte(),
+ byte: mode == Mode::Byte,
});
}
EscapeError::BareCarriageReturn => {
@@ -126,12 +129,15 @@ pub(crate) fn emit_unescape_error(
EscapeError::InvalidEscape => {
let (c, span) = last_char();
- let label =
- if mode.is_byte() { "unknown byte escape" } else { "unknown character escape" };
+ let label = if mode == Mode::Byte || mode == Mode::ByteStr {
+ "unknown byte escape"
+ } else {
+ "unknown character escape"
+ };
let ec = escaped_char(c);
- let mut diag = handler.struct_span_err(span, &format!("{}: `{}`", label, ec));
+ let mut diag = handler.struct_span_err(span, format!("{}: `{}`", label, ec));
diag.span_label(span, label);
- if c == '{' || c == '}' && !mode.is_byte() {
+ if c == '{' || c == '}' && matches!(mode, Mode::Str | Mode::RawStr) {
diag.help(
"if used in a formatting string, curly braces are escaped with `{{` and `}}`",
);
@@ -141,7 +147,7 @@ pub(crate) fn emit_unescape_error(
version control settings",
);
} else {
- if !mode.is_byte() {
+ if mode == Mode::Str || mode == Mode::Char {
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",
@@ -180,13 +186,13 @@ pub(crate) fn emit_unescape_error(
} else {
String::new()
};
- err.span_label(span, &format!("must be ASCII{}", postfix));
+ 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!(
+ format!(
"if you meant to use the unicode code point for {:?}, use a \\xHH escape",
c
),
@@ -200,10 +206,7 @@ pub(crate) fn emit_unescape_error(
utf8.push(c);
err.span_suggestion(
span,
- &format!(
- "if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes",
- c
- ),
+ format!("if you meant to use the UTF-8 encoding of {:?}, use \\xHH escapes", c),
utf8.as_bytes()
.iter()
.map(|b: &u8| format!("\\x{:X}", *b))
diff --git a/compiler/rustc_parse/src/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs
index 1f027c08f..829d9693e 100644
--- a/compiler/rustc_parse/src/lexer/unicode_chars.rs
+++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs
@@ -350,7 +350,7 @@ pub(super) fn check_for_substitution(
let Some((_, ascii_name, token)) = ASCII_ARRAY.iter().find(|&&(s, _, _)| s == ascii_str) else {
let msg = format!("substitution character not found for '{}'", ch);
- reader.sess.span_diagnostic.span_bug_no_panic(span, &msg);
+ reader.sess.span_diagnostic.span_bug_no_panic(span, msg);
return (None, None);
};
diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs
index 17466cd0e..25de78085 100644
--- a/compiler/rustc_parse/src/lib.rs
+++ b/compiler/rustc_parse/src/lib.rs
@@ -18,9 +18,9 @@ use rustc_ast::tokenstream::TokenStream;
use rustc_ast::{AttrItem, Attribute, MetaItem};
use rustc_ast_pretty::pprust;
use rustc_data_structures::sync::Lrc;
-use rustc_errors::{Applicability, Diagnostic, FatalError, Level, PResult};
+use rustc_errors::{Diagnostic, FatalError, Level, PResult};
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
use rustc_session::parse::ParseSess;
use rustc_span::{FileName, SourceFile, Span};
@@ -153,7 +153,7 @@ fn try_file_to_source_file(
) -> Result<Lrc<SourceFile>, Diagnostic> {
sess.source_map().load_file(path).map_err(|e| {
let msg = format!("couldn't read {}: {}", path.display(), e);
- let mut diag = Diagnostic::new(Level::Fatal, &msg);
+ let mut diag = Diagnostic::new(Level::Fatal, msg);
if let Some(sp) = spanopt {
diag.set_span(sp);
}
@@ -190,7 +190,7 @@ pub fn maybe_file_to_stream(
override_span: Option<Span>,
) -> Result<TokenStream, Vec<Diagnostic>> {
let src = source_file.src.as_ref().unwrap_or_else(|| {
- sess.span_diagnostic.bug(&format!(
+ sess.span_diagnostic.bug(format!(
"cannot lex `source_file` without source: {}",
sess.source_map().filename_for_diagnostics(&source_file.name)
));
@@ -243,12 +243,11 @@ pub fn parse_cfg_attr(
ast::AttrArgs::Delimited(ast::DelimArgs { dspan, delim, ref tokens })
if !tokens.is_empty() =>
{
- let msg = "wrong `cfg_attr` delimiters";
- crate::validate_attr::check_meta_bad_delim(parse_sess, dspan, delim, msg);
+ crate::validate_attr::check_cfg_attr_bad_delim(parse_sess, dspan, delim);
match parse_in(parse_sess, tokens.clone(), "`cfg_attr` input", |p| p.parse_cfg_attr()) {
Ok(r) => return Some(r),
Err(mut e) => {
- e.help(&format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
+ e.help(format!("the valid syntax is `{}`", CFG_ATTR_GRAMMAR_HELP))
.note(CFG_ATTR_NOTE_REF)
.emit();
}
@@ -265,15 +264,5 @@ const CFG_ATTR_NOTE_REF: &str = "for more information, visit \
#the-cfg_attr-attribute>";
fn error_malformed_cfg_attr_missing(span: Span, parse_sess: &ParseSess) {
- parse_sess
- .span_diagnostic
- .struct_span_err(span, "malformed `cfg_attr` attribute input")
- .span_suggestion(
- span,
- "missing condition and attribute",
- CFG_ATTR_GRAMMAR_HELP,
- Applicability::HasPlaceholders,
- )
- .note(CFG_ATTR_NOTE_REF)
- .emit();
+ parse_sess.emit_err(errors::MalformedCfgAttr { span, sugg: CFG_ATTR_GRAMMAR_HELP });
}
diff --git a/compiler/rustc_parse/src/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs
index e3e7c63e3..e1db19557 100644
--- a/compiler/rustc_parse/src/parser/attr.rs
+++ b/compiler/rustc_parse/src/parser/attr.rs
@@ -45,10 +45,10 @@ impl<'a> Parser<'a> {
Some(InnerAttrForbiddenReason::AfterOuterDocComment {
prev_doc_comment_span: prev_outer_attr_sp.unwrap(),
})
- } else if let Some(prev_outer_attr_sp) = prev_outer_attr_sp {
- Some(InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp })
} else {
- None
+ prev_outer_attr_sp.map(|prev_outer_attr_sp| {
+ InnerAttrForbiddenReason::AfterOuterAttribute { prev_outer_attr_sp }
+ })
};
let inner_parse_policy = InnerAttrPolicy::Forbidden(inner_error_reason);
just_parsed_doc_comment = false;
diff --git a/compiler/rustc_parse/src/parser/attr_wrapper.rs b/compiler/rustc_parse/src/parser/attr_wrapper.rs
index b0ab0f106..1e6ac5496 100644
--- a/compiler/rustc_parse/src/parser/attr_wrapper.rs
+++ b/compiler/rustc_parse/src/parser/attr_wrapper.rs
@@ -72,7 +72,7 @@ fn has_cfg_or_cfg_attr(attrs: &[Attribute]) -> bool {
// Therefore, the absence of a literal `cfg` or `cfg_attr` guarantees that
// we don't need to do any eager expansion.
attrs.iter().any(|attr| {
- attr.ident().map_or(false, |ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
+ attr.ident().is_some_and(|ident| ident.name == sym::cfg || ident.name == sym::cfg_attr)
})
}
diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs
index e03ce5d71..c14540396 100644
--- a/compiler/rustc_parse/src/parser/diagnostics.rs
+++ b/compiler/rustc_parse/src/parser/diagnostics.rs
@@ -4,7 +4,7 @@ use super::{
TokenExpectType, TokenType,
};
use crate::errors::{
- AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub,
+ AmbiguousPlus, AttributeOnParamType, BadQPathStage2, BadTypePlus, BadTypePlusSub, ColonAsSemi,
ComparisonOperatorsCannotBeChained, ComparisonOperatorsCannotBeChainedSugg,
ConstGenericWithoutBraces, ConstGenericWithoutBracesSugg, DocCommentDoesNotDocumentAnything,
DocCommentOnParamType, DoubleColonInBound, ExpectedIdentifier, ExpectedSemi, ExpectedSemiSugg,
@@ -13,7 +13,7 @@ use crate::errors::{
IncorrectUseOfAwait, ParenthesesInForHead, ParenthesesInForHeadSugg,
PatternMethodParamWithoutBody, QuestionMarkInType, QuestionMarkInTypeSugg, SelfParamNotFirst,
StructLiteralBodyWithoutPath, StructLiteralBodyWithoutPathSugg, StructLiteralNeedingParens,
- StructLiteralNeedingParensSugg, SuggEscapeIdentifier, SuggRemoveComma,
+ StructLiteralNeedingParensSugg, SuggAddMissingLetStmt, SuggEscapeIdentifier, SuggRemoveComma,
UnexpectedConstInGenericParam, UnexpectedConstParamDeclaration,
UnexpectedConstParamDeclarationSugg, UnmatchedAngleBrackets, UseEqInstead,
};
@@ -32,8 +32,8 @@ use rustc_ast::{
use rustc_ast_pretty::pprust;
use rustc_data_structures::fx::FxHashSet;
use rustc_errors::{
- pluralize, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed,
- FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
+ pluralize, AddToDiagnostic, Applicability, Diagnostic, DiagnosticBuilder, DiagnosticMessage,
+ ErrorGuaranteed, FatalError, Handler, IntoDiagnostic, MultiSpan, PResult,
};
use rustc_session::errors::ExprParenthesesNeeded;
use rustc_span::source_map::Spanned;
@@ -84,6 +84,7 @@ impl RecoverQPath for Ty {
}
impl RecoverQPath for Pat {
+ const PATH_STYLE: PathStyle = PathStyle::Pat;
fn to_ty(&self) -> Option<P<Ty>> {
self.to_ty()
}
@@ -206,11 +207,11 @@ struct MultiSugg {
impl MultiSugg {
fn emit(self, err: &mut Diagnostic) {
- err.multipart_suggestion(&self.msg, self.patches, self.applicability);
+ err.multipart_suggestion(self.msg, self.patches, self.applicability);
}
fn emit_verbose(self, err: &mut Diagnostic) {
- err.multipart_suggestion_verbose(&self.msg, self.patches, self.applicability);
+ err.multipart_suggestion_verbose(self.msg, self.patches, self.applicability);
}
}
@@ -237,6 +238,7 @@ impl<'a> DerefMut for SnapshotParser<'a> {
impl<'a> Parser<'a> {
#[rustc_lint_diagnostics]
+ #[track_caller]
pub fn struct_span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -570,15 +572,13 @@ impl<'a> Parser<'a> {
let expect = tokens_to_string(&expected);
let actual = super::token_descr(&self.token);
let (msg_exp, (label_sp, label_exp)) = if expected.len() > 1 {
+ let fmt = format!("expected one of {expect}, found {actual}");
let short_expect = if expected.len() > 6 {
format!("{} possible tokens", expected.len())
} else {
- expect.clone()
+ expect
};
- (
- format!("expected one of {expect}, found {actual}"),
- (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")),
- )
+ (fmt, (self.prev_token.span.shrink_to_hi(), format!("expected one of {short_expect}")))
} else if expected.is_empty() {
(
format!("unexpected token: {actual}"),
@@ -592,13 +592,13 @@ impl<'a> Parser<'a> {
};
self.last_unexpected_token_span = Some(self.token.span);
// FIXME: translation requires list formatting (for `expect`)
- let mut err = self.struct_span_err(self.token.span, &msg_exp);
+ let mut err = self.struct_span_err(self.token.span, msg_exp);
if let TokenKind::Ident(symbol, _) = &self.prev_token.kind {
if ["def", "fun", "func", "function"].contains(&symbol.as_str()) {
err.span_suggestion_short(
self.prev_token.span,
- &format!("write `fn` instead of `{symbol}` to declare a function"),
+ format!("write `fn` instead of `{symbol}` to declare a function"),
"fn",
Applicability::MachineApplicable,
);
@@ -665,7 +665,6 @@ impl<'a> Parser<'a> {
err.span_label(sp, label_exp);
err.span_label(self.token.span, "unexpected token");
}
- self.maybe_annotate_with_ascription(&mut err, false);
Err(err)
}
@@ -697,13 +696,13 @@ impl<'a> Parser<'a> {
err.set_span(span);
err.span_suggestion(
span,
- &format!("remove the extra `#`{}", pluralize!(count)),
+ format!("remove the extra `#`{}", pluralize!(count)),
"",
Applicability::MachineApplicable,
);
err.span_label(
str_span,
- &format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
+ format!("this raw string started with {n_hashes} `#`{}", pluralize!(n_hashes)),
);
true
}
@@ -790,59 +789,6 @@ impl<'a> Parser<'a> {
None
}
- pub fn maybe_annotate_with_ascription(
- &mut self,
- err: &mut Diagnostic,
- maybe_expected_semicolon: bool,
- ) {
- if let Some((sp, likely_path)) = self.last_type_ascription.take() {
- let sm = self.sess.source_map();
- let next_pos = sm.lookup_char_pos(self.token.span.lo());
- let op_pos = sm.lookup_char_pos(sp.hi());
-
- let allow_unstable = self.sess.unstable_features.is_nightly_build();
-
- if likely_path {
- err.span_suggestion(
- sp,
- "maybe write a path separator here",
- "::",
- if allow_unstable {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- },
- );
- self.sess.type_ascription_path_suggestions.borrow_mut().insert(sp);
- } else if op_pos.line != next_pos.line && maybe_expected_semicolon {
- err.span_suggestion(
- sp,
- "try using a semicolon",
- ";",
- Applicability::MaybeIncorrect,
- );
- } else if allow_unstable {
- err.span_label(sp, "tried to parse a type due to this type ascription");
- } else {
- err.span_label(sp, "tried to parse a type due to this");
- }
- if allow_unstable {
- // Give extra information about type ascription only if it's a nightly compiler.
- err.note(
- "`#![feature(type_ascription)]` lets you annotate an expression with a type: \
- `<expr>: <type>`",
- );
- if !likely_path {
- // Avoid giving too much info when it was likely an unrelated typo.
- err.note(
- "see issue #23416 <https://github.com/rust-lang/rust/issues/23416> \
- for more information",
- );
- }
- }
- }
- }
-
/// Eats and discards tokens until one of `kets` is encountered. Respects token trees,
/// passes through any errors encountered. Used for error recovery.
pub(super) fn eat_to_tokens(&mut self, kets: &[&TokenKind]) {
@@ -899,7 +845,7 @@ impl<'a> Parser<'a> {
//
// `x.foo::<u32>>>(3)`
let parsed_angle_bracket_args =
- segment.args.as_ref().map_or(false, |args| args.is_angle_bracketed());
+ segment.args.as_ref().is_some_and(|args| args.is_angle_bracketed());
debug!(
"check_trailing_angle_brackets: parsed_angle_bracket_args={:?}",
@@ -1061,6 +1007,31 @@ impl<'a> Parser<'a> {
Err(e)
}
+ /// Suggest add the missing `let` before the identifier in stmt
+ /// `a: Ty = 1` -> `let a: Ty = 1`
+ pub(super) fn suggest_add_missing_let_for_stmt(
+ &mut self,
+ err: &mut DiagnosticBuilder<'a, ErrorGuaranteed>,
+ ) {
+ if self.token == token::Colon {
+ let prev_span = self.prev_token.span.shrink_to_lo();
+ let snapshot = self.create_snapshot_for_diagnostic();
+ self.bump();
+ match self.parse_ty() {
+ Ok(_) => {
+ if self.token == token::Eq {
+ let sugg = SuggAddMissingLetStmt { span: prev_span };
+ sugg.add_to_diagnostic(err);
+ }
+ }
+ Err(e) => {
+ e.cancel();
+ }
+ }
+ self.restore_snapshot(snapshot);
+ }
+ }
+
/// Check to see if a pair of chained operators looks like an attempt at chained comparison,
/// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or
/// parenthesising the leftmost comparison.
@@ -1339,7 +1310,7 @@ impl<'a> Parser<'a> {
}
self.bump(); // `+`
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
let sum_span = ty.span.to(self.prev_token.span);
let sub = match &ty.kind {
@@ -1415,12 +1386,12 @@ impl<'a> Parser<'a> {
) -> PResult<'a, P<Expr>> {
let mut err = self.struct_span_err(
op_span,
- &format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
+ format!("Rust has no {} {} operator", kind.fixity, kind.op.name()),
);
- err.span_label(op_span, &format!("not a valid {} operator", kind.fixity));
+ err.span_label(op_span, format!("not a valid {} operator", kind.fixity));
let help_base_case = |mut err: DiagnosticBuilder<'_, _>, base| {
- err.help(&format!("use `{}= 1` instead", kind.op.chr()));
+ err.help(format!("use `{}= 1` instead", kind.op.chr()));
err.emit();
Ok(base)
};
@@ -1609,7 +1580,7 @@ impl<'a> Parser<'a> {
_ => this_token_str,
},
);
- let mut err = self.struct_span_err(sp, &msg);
+ let mut err = self.struct_span_err(sp, msg);
let label_exp = format!("expected `{token_str}`");
let sm = self.sess.source_map();
if !sm.is_multiline(prev_sp.until(sp)) {
@@ -1624,12 +1595,36 @@ impl<'a> Parser<'a> {
}
pub(super) fn expect_semi(&mut self) -> PResult<'a, ()> {
- if self.eat(&token::Semi) {
+ if self.eat(&token::Semi) || self.recover_colon_as_semi() {
return Ok(());
}
self.expect(&token::Semi).map(drop) // Error unconditionally
}
+ pub(super) fn recover_colon_as_semi(&mut self) -> bool {
+ let line_idx = |span: Span| {
+ self.sess
+ .source_map()
+ .span_to_lines(span)
+ .ok()
+ .and_then(|lines| Some(lines.lines.get(0)?.line_index))
+ };
+
+ if self.may_recover()
+ && self.token == token::Colon
+ && self.look_ahead(1, |next| line_idx(self.token.span) < line_idx(next.span))
+ {
+ self.sess.emit_err(ColonAsSemi {
+ span: self.token.span,
+ type_ascription: self.sess.unstable_features.is_nightly_build().then_some(()),
+ });
+ self.bump();
+ return true;
+ }
+
+ false
+ }
+
/// Consumes alternative await syntaxes like `await!(<expr>)`, `await <expr>`,
/// `await? <expr>`, `await(<expr>)`, and `await { <expr> }`.
pub(super) fn recover_incorrect_await_syntax(
@@ -1648,7 +1643,7 @@ impl<'a> Parser<'a> {
// Avoid knock-down errors as we don't know whether to interpret this as `foo().await?`
// or `foo()?.await` (the very reason we went with postfix syntax 😅).
ExprKind::Try(_) => ExprKind::Err,
- _ => ExprKind::Await(expr),
+ _ => ExprKind::Await(expr, await_sp),
};
let expr = self.mk_expr(lo.to(sp), kind);
self.maybe_recover_from_bad_qpath(expr)
@@ -1736,7 +1731,7 @@ impl<'a> Parser<'a> {
Applicability::MachineApplicable,
);
}
- err.span_suggestion(lo.shrink_to_lo(), &format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
+ err.span_suggestion(lo.shrink_to_lo(), format!("{prefix}you can still access the deprecated `try!()` macro using the \"raw identifier\" syntax"), "r#", Applicability::MachineApplicable);
err.emit();
Ok(self.mk_expr_err(lo.to(hi)))
} else {
@@ -1792,24 +1787,6 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn could_ascription_be_path(&self, node: &ast::ExprKind) -> bool {
- (self.token == token::Lt && // `foo:<bar`, likely a typoed turbofish.
- self.look_ahead(1, |t| t.is_ident() && !t.is_reserved_ident()))
- || self.token.is_ident() &&
- matches!(node, ast::ExprKind::Path(..) | ast::ExprKind::Field(..)) &&
- !self.token.is_reserved_ident() && // v `foo:bar(baz)`
- self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Parenthesis))
- || self.look_ahead(1, |t| t == &token::OpenDelim(Delimiter::Brace)) // `foo:bar {`
- || self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar::<baz`
- self.look_ahead(2, |t| t == &token::Lt) &&
- self.look_ahead(3, |t| t.is_ident())
- || self.look_ahead(1, |t| t == &token::Colon) && // `foo:bar:baz`
- self.look_ahead(2, |t| t.is_ident())
- || self.look_ahead(1, |t| t == &token::ModSep)
- && (self.look_ahead(2, |t| t.is_ident()) || // `foo:bar::baz`
- self.look_ahead(2, |t| t == &token::Lt)) // `foo:bar::<baz>`
- }
-
pub(super) fn recover_seq_parse_error(
&mut self,
delim: Delimiter,
@@ -1904,7 +1881,6 @@ impl<'a> Parser<'a> {
&& brace_depth == 0
&& bracket_depth == 0 =>
{
- debug!("recover_stmt_ return - Semi");
break;
}
_ => self.bump(),
@@ -2110,7 +2086,7 @@ impl<'a> Parser<'a> {
format!("expected expression, found {}", super::token_descr(&self.token),),
),
};
- let mut err = self.struct_span_err(span, &msg);
+ let mut err = self.struct_span_err(span, msg);
let sp = self.sess.source_map().start_point(self.token.span);
if let Some(sp) = self.sess.ambiguous_block_expr_parse.borrow().get(&sp) {
err.subdiagnostic(ExprParenthesesNeeded::surrounding(*sp));
@@ -2181,7 +2157,7 @@ impl<'a> Parser<'a> {
// arguments after a comma.
let mut err = self.struct_span_err(
self.token.span,
- &format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
+ format!("expected one of `,` or `>`, found {}", super::token_descr(&self.token)),
);
err.span_label(self.token.span, "expected one of `,` or `>`");
match self.recover_const_arg(arg.span(), err) {
@@ -2608,7 +2584,7 @@ impl<'a> Parser<'a> {
let mut err = self.struct_span_err(comma_span, "unexpected `,` in pattern");
if let Ok(seq_snippet) = self.span_to_snippet(seq_span) {
err.multipart_suggestion(
- &format!(
+ format!(
"try adding parentheses to match on a tuple{}",
if let CommaRecoveryMode::LikelyTuple = rt { "" } else { "..." },
),
@@ -2634,7 +2610,7 @@ impl<'a> Parser<'a> {
let TyKind::Path(qself, path) = &ty.kind else { return Ok(()) };
let qself_position = qself.as_ref().map(|qself| qself.position);
for (i, segments) in path.segments.windows(2).enumerate() {
- if qself_position.map(|pos| i < pos).unwrap_or(false) {
+ if qself_position.is_some_and(|pos| i < pos) {
continue;
}
if let [a, b] = segments {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 03c82fbd3..1b28f3c97 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -174,10 +174,8 @@ impl<'a> Parser<'a> {
self.parse_expr_prefix(attrs)?
}
};
- let last_type_ascription_set = self.last_type_ascription.is_some();
if !self.should_continue_as_assoc_expr(&lhs) {
- self.last_type_ascription = None;
return Ok(lhs);
}
@@ -301,9 +299,6 @@ impl<'a> Parser<'a> {
if op == AssocOp::As {
lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Cast)?;
continue;
- } else if op == AssocOp::Colon {
- lhs = self.parse_assoc_op_ascribe(lhs, lhs_span)?;
- continue;
} else if op == AssocOp::DotDot || op == AssocOp::DotDotEq {
// If we didn't have to handle `x..`/`x..=`, it would be pretty easy to
// generalise it to the Fixity::None code.
@@ -364,7 +359,7 @@ impl<'a> Parser<'a> {
let aopexpr = self.mk_assign_op(source_map::respan(cur_op_span, aop), lhs, rhs);
self.mk_expr(span, aopexpr)
}
- AssocOp::As | AssocOp::Colon | AssocOp::DotDot | AssocOp::DotDotEq => {
+ AssocOp::As | AssocOp::DotDot | AssocOp::DotDotEq => {
self.span_bug(span, "AssocOp should have been handled by special case")
}
};
@@ -373,9 +368,7 @@ impl<'a> Parser<'a> {
break;
}
}
- if last_type_ascription_set {
- self.last_type_ascription = None;
- }
+
Ok(lhs)
}
@@ -743,7 +736,7 @@ impl<'a> Parser<'a> {
(
// `foo: `
ExprKind::Path(None, ast::Path { segments, .. }),
- TokenKind::Ident(kw::For | kw::Loop | kw::While, false),
+ token::Ident(kw::For | kw::Loop | kw::While, false),
) if segments.len() == 1 => {
let snapshot = self.create_snapshot_for_diagnostic();
let label = Label {
@@ -838,33 +831,31 @@ impl<'a> Parser<'a> {
&mut self,
cast_expr: P<Expr>,
) -> PResult<'a, P<Expr>> {
+ if let ExprKind::Type(_, _) = cast_expr.kind {
+ panic!("ExprKind::Type must not be parsed");
+ }
+
let span = cast_expr.span;
- let (cast_kind, maybe_ascription_span) =
- if let ExprKind::Type(ascripted_expr, _) = &cast_expr.kind {
- ("type ascription", Some(ascripted_expr.span.shrink_to_hi().with_hi(span.hi())))
- } else {
- ("cast", None)
- };
let with_postfix = self.parse_expr_dot_or_call_with_(cast_expr, span)?;
// Check if an illegal postfix operator has been added after the cast.
// If the resulting expression is not a cast, it is an illegal postfix operator.
- if !matches!(with_postfix.kind, ExprKind::Cast(_, _) | ExprKind::Type(_, _)) {
+ if !matches!(with_postfix.kind, ExprKind::Cast(_, _)) {
let msg = format!(
- "{cast_kind} cannot be followed by {}",
+ "cast cannot be followed by {}",
match with_postfix.kind {
ExprKind::Index(_, _) => "indexing",
ExprKind::Try(_) => "`?`",
ExprKind::Field(_, _) => "a field access",
ExprKind::MethodCall(_) => "a method call",
ExprKind::Call(_, _) => "a function call",
- ExprKind::Await(_) => "`.await`",
+ ExprKind::Await(_, _) => "`.await`",
ExprKind::Err => return Ok(with_postfix),
_ => unreachable!("parse_dot_or_call_expr_with_ shouldn't produce this"),
}
);
- let mut err = self.struct_span_err(span, &msg);
+ let mut err = self.struct_span_err(span, msg);
let suggest_parens = |err: &mut Diagnostic| {
let suggestions = vec![
@@ -878,44 +869,13 @@ impl<'a> Parser<'a> {
);
};
- // If type ascription is "likely an error", the user will already be getting a useful
- // help message, and doesn't need a second.
- if self.last_type_ascription.map_or(false, |last_ascription| last_ascription.1) {
- self.maybe_annotate_with_ascription(&mut err, false);
- } else if let Some(ascription_span) = maybe_ascription_span {
- let is_nightly = self.sess.unstable_features.is_nightly_build();
- if is_nightly {
- suggest_parens(&mut err);
- }
- err.span_suggestion(
- ascription_span,
- &format!(
- "{}remove the type ascription",
- if is_nightly { "alternatively, " } else { "" }
- ),
- "",
- if is_nightly {
- Applicability::MaybeIncorrect
- } else {
- Applicability::MachineApplicable
- },
- );
- } else {
- suggest_parens(&mut err);
- }
+ suggest_parens(&mut err);
+
err.emit();
};
Ok(with_postfix)
}
- fn parse_assoc_op_ascribe(&mut self, lhs: P<Expr>, lhs_span: Span) -> PResult<'a, P<Expr>> {
- let maybe_path = self.could_ascription_be_path(&lhs.kind);
- self.last_type_ascription = Some((self.prev_token.span, maybe_path));
- let lhs = self.parse_assoc_op_cast(lhs, lhs_span, ExprKind::Type)?;
- self.sess.gated_spans.gate(sym::type_ascription, lhs.span);
- Ok(lhs)
- }
-
/// Parse `& mut? <expr>` or `& raw [ const | mut ] <expr>`.
fn parse_expr_borrow(&mut self, lo: Span) -> PResult<'a, (Span, ExprKind)> {
self.expect_and()?;
@@ -1010,7 +970,7 @@ impl<'a> Parser<'a> {
};
if has_dot {
// expr.f
- e = self.parse_expr_dot_suffix(lo, e)?;
+ e = self.parse_dot_suffix_expr(lo, e)?;
continue;
}
if self.expr_is_complete(&e) {
@@ -1024,13 +984,7 @@ impl<'a> Parser<'a> {
}
}
- fn look_ahead_type_ascription_as_field(&mut self) -> bool {
- self.look_ahead(1, |t| t.is_ident())
- && self.look_ahead(2, |t| t == &token::Colon)
- && self.look_ahead(3, |t| t.can_begin_expr())
- }
-
- fn parse_expr_dot_suffix(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
+ fn parse_dot_suffix_expr(&mut self, lo: Span, base: P<Expr>) -> PResult<'a, P<Expr>> {
match self.token.uninterpolate().kind {
token::Ident(..) => self.parse_dot_suffix(base, lo),
token::Literal(token::Lit { kind: token::Integer, symbol, suffix }) => {
@@ -1183,9 +1137,7 @@ impl<'a> Parser<'a> {
/// Parse a function call expression, `expr(...)`.
fn parse_expr_fn_call(&mut self, lo: Span, fun: P<Expr>) -> P<Expr> {
- let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis)
- && self.look_ahead_type_ascription_as_field()
- {
+ let snapshot = if self.token.kind == token::OpenDelim(Delimiter::Parenthesis) {
Some((self.create_snapshot_for_diagnostic(), fun.kind.clone()))
} else {
None
@@ -1216,7 +1168,6 @@ impl<'a> Parser<'a> {
if !self.may_recover() {
return None;
}
-
match (seq.as_mut(), snapshot) {
(Err(err), Some((mut snapshot, ExprKind::Path(None, path)))) => {
snapshot.bump(); // `(`
@@ -1229,11 +1180,15 @@ impl<'a> Parser<'a> {
self.restore_snapshot(snapshot);
let close_paren = self.prev_token.span;
let span = lo.to(close_paren);
+ // filter shorthand fields
+ let fields: Vec<_> =
+ fields.into_iter().filter(|field| !field.is_shorthand).collect();
+
if !fields.is_empty() &&
// `token.kind` should not be compared here.
// This is because the `snapshot.token.kind` is treated as the same as
// that of the open delim in `TokenTreesReader::parse_token_tree`, even if they are different.
- self.span_to_snippet(close_paren).map_or(false, |snippet| snippet == ")")
+ self.span_to_snippet(close_paren).is_ok_and(|snippet| snippet == ")")
{
let mut replacement_err = errors::ParenthesesWithStructFields {
span,
@@ -1260,9 +1215,7 @@ impl<'a> Parser<'a> {
return Some(self.mk_expr_err(span));
}
Ok(_) => {}
- Err(mut err) => {
- err.emit();
- }
+ Err(err) => err.cancel(),
}
}
_ => {}
@@ -1351,6 +1304,8 @@ impl<'a> Parser<'a> {
})
} else if self.check(&token::OpenDelim(Delimiter::Bracket)) {
self.parse_expr_array_or_repeat(Delimiter::Bracket)
+ } else if self.is_builtin() {
+ self.parse_expr_builtin()
} else if self.check_path() {
self.parse_expr_path_start()
} else if self.check_keyword(kw::Move)
@@ -1499,8 +1454,19 @@ impl<'a> Parser<'a> {
}
fn parse_expr_path_start(&mut self) -> PResult<'a, P<Expr>> {
+ let maybe_eq_tok = self.prev_token.clone();
let (qself, path) = if self.eat_lt() {
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let lt_span = self.prev_token.span;
+ let (qself, path) = self.parse_qpath(PathStyle::Expr).map_err(|mut err| {
+ // Suggests using '<=' if there is an error parsing qpath when the previous token
+ // is an '=' token. Only emits suggestion if the '<' token and '=' token are
+ // directly adjacent (i.e. '=<')
+ if maybe_eq_tok.kind == TokenKind::Eq && maybe_eq_tok.span.hi() == lt_span.lo() {
+ let eq_lt = maybe_eq_tok.span.to(lt_span);
+ err.span_suggestion(eq_lt, "did you mean", "<=", Applicability::Unspecified);
+ }
+ err
+ })?;
(Some(qself), path)
} else {
(None, self.parse_path(PathStyle::Expr)?)
@@ -1516,7 +1482,6 @@ impl<'a> Parser<'a> {
let mac = P(MacCall {
path,
args: self.parse_delim_args()?,
- prior_type_ascription: self.last_type_ascription,
});
(lo.to(self.prev_token.span), ExprKind::MacCall(mac))
} else if self.check(&token::OpenDelim(Delimiter::Brace))
@@ -1535,7 +1500,7 @@ impl<'a> Parser<'a> {
}
/// Parse `'label: $expr`. The label is already parsed.
- fn parse_expr_labeled(
+ pub(super) fn parse_expr_labeled(
&mut self,
label_: Label,
mut consume_colon: bool,
@@ -1807,6 +1772,61 @@ impl<'a> Parser<'a> {
self.maybe_recover_from_bad_qpath(expr)
}
+ /// Parse `builtin # ident(args,*)`.
+ fn parse_expr_builtin(&mut self) -> PResult<'a, P<Expr>> {
+ self.parse_builtin(|this, lo, ident| {
+ if ident.name == sym::offset_of {
+ return Ok(Some(this.parse_expr_offset_of(lo)?));
+ }
+
+ Ok(None)
+ })
+ }
+
+ pub(crate) fn parse_builtin<T>(
+ &mut self,
+ parse: impl FnOnce(&mut Parser<'a>, Span, Ident) -> PResult<'a, Option<T>>,
+ ) -> PResult<'a, T> {
+ let lo = self.token.span;
+
+ self.bump(); // `builtin`
+ self.bump(); // `#`
+
+ let Some((ident, false)) = self.token.ident() else {
+ let err = errors::ExpectedBuiltinIdent { span: self.token.span }
+ .into_diagnostic(&self.sess.span_diagnostic);
+ return Err(err);
+ };
+ self.sess.gated_spans.gate(sym::builtin_syntax, ident.span);
+ self.bump();
+
+ self.expect(&TokenKind::OpenDelim(Delimiter::Parenthesis))?;
+ let ret = if let Some(res) = parse(self, lo, ident)? {
+ Ok(res)
+ } else {
+ let err = errors::UnknownBuiltinConstruct { span: lo.to(ident.span), name: ident.name }
+ .into_diagnostic(&self.sess.span_diagnostic);
+ return Err(err);
+ };
+ self.expect(&TokenKind::CloseDelim(Delimiter::Parenthesis))?;
+
+ ret
+ }
+
+ pub(crate) fn parse_expr_offset_of(&mut self, lo: Span) -> PResult<'a, P<Expr>> {
+ let container = self.parse_ty()?;
+ self.expect(&TokenKind::Comma)?;
+
+ let seq_sep = SeqSep { sep: Some(token::Dot), trailing_sep_allowed: false };
+ let (fields, _trailing, _recovered) = self.parse_seq_to_before_end(
+ &TokenKind::CloseDelim(Delimiter::Parenthesis),
+ seq_sep,
+ Parser::parse_field_name,
+ )?;
+ let span = lo.to(self.token.span);
+ Ok(self.mk_expr(span, ExprKind::OffsetOf(container, fields.to_vec().into())))
+ }
+
/// Returns a string literal if the next token is a string literal.
/// In case of error returns `Some(lit)` if the next token is a literal with a wrong kind,
/// and returns `None` if the next token is not literal at all.
@@ -1855,7 +1875,7 @@ impl<'a> Parser<'a> {
let token = self.token.clone();
let err = |self_: &Self| {
let msg = format!("unexpected token: {}", super::token_descr(&token));
- self_.struct_span_err(token.span, &msg)
+ self_.struct_span_err(token.span, msg)
};
// On an error path, eagerly consider a lifetime to be an unclosed character lit
if self.token.is_lifetime() {
@@ -1922,6 +1942,7 @@ impl<'a> Parser<'a> {
let recovered = self.recover_after_dot();
let token = recovered.as_ref().unwrap_or(&self.token);
let span = token.span;
+
token::Lit::from_token(token).map(|token_lit| {
self.bump();
(token_lit, span)
@@ -2057,7 +2078,7 @@ impl<'a> Parser<'a> {
// Therefore, `token.kind` should not be compared here.
if snapshot
.span_to_snippet(snapshot.token.span)
- .map_or(false, |snippet| snippet == "]") =>
+ .is_ok_and(|snippet| snippet == "]") =>
{
return Err(errors::MissingSemicolonBeforeArray {
open_delim: open_delim_span,
@@ -2752,7 +2773,7 @@ impl<'a> Parser<'a> {
// We might have a `=>` -> `=` or `->` typo (issue #89396).
if TokenKind::FatArrow
.similar_tokens()
- .map_or(false, |similar_tokens| similar_tokens.contains(&this.token.kind))
+ .is_some_and(|similar_tokens| similar_tokens.contains(&this.token.kind))
{
err.span_suggestion(
this.token.span,
@@ -2875,6 +2896,10 @@ impl<'a> Parser<'a> {
})
}
+ pub(crate) fn is_builtin(&self) -> bool {
+ self.token.is_keyword(kw::Builtin) && self.look_ahead(1, |t| *t == token::Pound)
+ }
+
/// Parses a `try {...}` expression (`try` token already eaten).
fn parse_try_block(&mut self, span_lo: Span) -> PResult<'a, P<Expr>> {
let (attrs, body) = self.parse_inner_attrs_and_block()?;
@@ -3013,6 +3038,11 @@ impl<'a> Parser<'a> {
} else {
e.span_label(pth.span, "while parsing this struct");
}
+
+ if !recover {
+ return Err(e);
+ }
+
e.emit();
// If the next token is a comma, then try to parse
@@ -3024,11 +3054,12 @@ impl<'a> Parser<'a> {
break;
}
}
+
None
}
};
- let is_shorthand = parsed_field.as_ref().map_or(false, |f| f.is_shorthand);
+ let is_shorthand = parsed_field.as_ref().is_some_and(|f| f.is_shorthand);
// A shorthand field can be turned into a full field with `:`.
// We should point this out.
self.check_or_expected(!is_shorthand, TokenType::Token(token::Colon));
@@ -3151,14 +3182,10 @@ impl<'a> Parser<'a> {
let label = format!("'{}", ident.name);
let ident = Ident { name: Symbol::intern(&label), span: ident.span };
- self.struct_span_err(ident.span, "expected a label, found an identifier")
- .span_suggestion(
- ident.span,
- "labels start with a tick",
- label,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::ExpectedLabelFoundIdent {
+ span: ident.span,
+ start: ident.span.shrink_to_lo(),
+ });
Label { ident }
}
@@ -3256,7 +3283,7 @@ impl<'a> Parser<'a> {
fn mk_await_expr(&mut self, self_arg: P<Expr>, lo: Span) -> P<Expr> {
let span = lo.to(self.prev_token.span);
- let await_expr = self.mk_expr(span, ExprKind::Await(self_arg));
+ let await_expr = self.mk_expr(span, ExprKind::Await(self_arg, self.prev_token.span));
self.recover_from_await_method_call();
await_expr
}
diff --git a/compiler/rustc_parse/src/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs
index f8ef1307c..cd779b0b4 100644
--- a/compiler/rustc_parse/src/parser/generics.rs
+++ b/compiler/rustc_parse/src/parser/generics.rs
@@ -1,5 +1,5 @@
use crate::errors::{
- MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
+ self, MultipleWhereClauses, UnexpectedDefaultValueForLifetimeInGenericParameters,
UnexpectedSelfInGenericParameters, WhereClauseBeforeTupleStructBody,
WhereClauseBeforeTupleStructBodySugg,
};
@@ -78,7 +78,7 @@ impl<'a> Parser<'a> {
}
self.restore_snapshot(snapshot);
}
- self.parse_generic_bounds(colon_span)?
+ self.parse_generic_bounds()?
} else {
Vec::new()
};
@@ -181,12 +181,9 @@ impl<'a> Parser<'a> {
let snapshot = this.create_snapshot_for_diagnostic();
match this.parse_ty_where_predicate() {
Ok(where_predicate) => {
- this.struct_span_err(
- where_predicate.span(),
- "bounds on associated types do not belong here",
- )
- .span_label(where_predicate.span(), "belongs in `where` clause")
- .emit();
+ this.sess.emit_err(errors::BadAssocTypeBounds {
+ span: where_predicate.span(),
+ });
// FIXME - try to continue parsing other generics?
return Ok((None, TrailingToken::None));
}
@@ -201,22 +198,11 @@ impl<'a> Parser<'a> {
// Check for trailing attributes and stop parsing.
if !attrs.is_empty() {
if !params.is_empty() {
- this.struct_span_err(
- attrs[0].span,
- "trailing attribute after generic parameter",
- )
- .span_label(attrs[0].span, "attributes must go before parameters")
- .emit();
+ this.sess
+ .emit_err(errors::AttrAfterGeneric { span: attrs[0].span });
} else {
- this.struct_span_err(
- attrs[0].span,
- "attribute without generic parameters",
- )
- .span_label(
- attrs[0].span,
- "attributes are only permitted when preceding parameters",
- )
- .emit();
+ this.sess
+ .emit_err(errors::AttrWithoutGenerics { span: attrs[0].span });
}
}
return Ok((None, TrailingToken::None));
@@ -304,12 +290,7 @@ impl<'a> Parser<'a> {
// change we parse those generics now, but report an error.
if self.choose_generics_over_qpath(0) {
let generics = self.parse_generics()?;
- self.struct_span_err(
- generics.span,
- "generic parameters on `where` clauses are reserved for future use",
- )
- .span_label(generics.span, "currently unsupported")
- .emit();
+ self.sess.emit_err(errors::WhereOnGenerics { span: generics.span });
}
loop {
@@ -438,7 +419,7 @@ impl<'a> Parser<'a> {
// or with mandatory equality sign and the second type.
let ty = self.parse_ty_for_where_clause()?;
if self.eat(&token::Colon) {
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
Ok(ast::WherePredicate::BoundPredicate(ast::WhereBoundPredicate {
span: lo.to(self.prev_token.span),
bound_generic_params: lifetime_defs,
@@ -472,6 +453,8 @@ impl<'a> Parser<'a> {
// `<` (LIFETIME|IDENT) `:` - generic parameter with bounds
// `<` (LIFETIME|IDENT) `=` - generic parameter with a default
// `<` const - generic const parameter
+ // `<` IDENT `?` - RECOVERY for `impl<T ?Bound` missing a `:`, meant to
+ // avoid the `T?` to `Option<T>` recovery for types.
// The only truly ambiguous case is
// `<` IDENT `>` `::` IDENT ...
// we disambiguate it in favor of generics (`impl<T> ::absolute::Path<T> { ... }`)
@@ -482,6 +465,9 @@ impl<'a> Parser<'a> {
|| self.look_ahead(start + 1, |t| t.is_lifetime() || t.is_ident())
&& self.look_ahead(start + 2, |t| {
matches!(t.kind, token::Gt | token::Comma | token::Colon | token::Eq)
+ // Recovery-only branch -- this could be removed,
+ // since it only affects diagnostics currently.
+ || matches!(t.kind, token::Question)
})
|| self.is_keyword_ahead(start + 1, &[kw::Const]))
}
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 6422b8ac1..3783ec41b 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -71,7 +71,7 @@ impl<'a> Parser<'a> {
if !self.eat(term) {
let token_str = super::token_descr(&self.token);
if !self.maybe_consume_incorrect_semicolon(&items) {
- let msg = &format!("expected item, found {token_str}");
+ let msg = format!("expected item, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
let label = if self.is_kw_followed_by_ident(kw::Let) {
"consider using `const` or `static` instead of `let` for global variables"
@@ -181,11 +181,11 @@ impl<'a> Parser<'a> {
/// Error in-case `default` was parsed in an in-appropriate context.
fn error_on_unconsumed_default(&self, def: Defaultness, kind: &ItemKind) {
if let Defaultness::Default(span) = def {
- let msg = format!("{} {} cannot be `default`", kind.article(), kind.descr());
- self.struct_span_err(span, &msg)
- .span_label(span, "`default` because of this")
- .note("only associated `fn`, `const`, and `type` items can be `default`")
- .emit();
+ self.sess.emit_err(errors::InappropriateDefault {
+ span,
+ article: kind.article(),
+ descr: kind.descr(),
+ });
}
}
@@ -265,6 +265,9 @@ impl<'a> Parser<'a> {
// UNION ITEM
self.bump(); // `union`
self.parse_item_union()?
+ } else if self.is_builtin() {
+ // BUILTIN# ITEM
+ return self.parse_item_builtin();
} else if self.eat_keyword(kw::Macro) {
// MACROS 2.0 ITEM
self.parse_item_decl_macro(lo)?
@@ -310,14 +313,7 @@ impl<'a> Parser<'a> {
self.bump();
match self.parse_use_item() {
Ok(u) => {
- self.struct_span_err(span, format!("expected item, found {token_name}"))
- .span_suggestion_short(
- span,
- "items are imported using the `use` keyword",
- "use",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::RecoverImportAsUse { span, token_name });
Ok(Some(u))
}
Err(e) => {
@@ -441,6 +437,11 @@ impl<'a> Parser<'a> {
}
}
+ fn parse_item_builtin(&mut self) -> PResult<'a, Option<ItemInfo>> {
+ // To be expanded
+ return Ok(None);
+ }
+
/// Parses an item macro, e.g., `item!();`.
fn parse_item_macro(&mut self, vis: &Visibility) -> PResult<'a, MacCall> {
let path = self.parse_path(PathStyle::Mod)?; // `foo::bar`
@@ -450,7 +451,7 @@ impl<'a> Parser<'a> {
Ok(args) => {
self.eat_semi_for_macro_if_needed(&args);
self.complain_if_pub_macro(vis, false);
- Ok(MacCall { path, args, prior_type_ascription: self.last_type_ascription })
+ Ok(MacCall { path, args })
}
Err(mut err) => {
@@ -602,10 +603,24 @@ impl<'a> Parser<'a> {
let path = match ty_first.kind {
// This notably includes paths passed through `ty` macro fragments (#46438).
TyKind::Path(None, path) => path,
- _ => {
- self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
- span: ty_first.span,
- });
+ other => {
+ if let TyKind::ImplTrait(_, bounds) = other
+ && let [bound] = bounds.as_slice()
+ {
+ // Suggest removing extra `impl` keyword:
+ // `impl<T: Default> impl Default for Wrapper<T>`
+ // ^^^^^
+ let extra_impl_kw = ty_first.span.until(bound.span());
+ self.sess
+ .emit_err(errors::ExtraImplKeywordInTraitImpl {
+ extra_impl_kw,
+ impl_trait_span: ty_first.span
+ });
+ } else {
+ self.sess.emit_err(errors::ExpectedTraitInTraitImplFoundType {
+ span: ty_first.span,
+ });
+ }
err_path(ty_first.span)
}
};
@@ -684,7 +699,7 @@ impl<'a> Parser<'a> {
// ```
&& self
.span_to_snippet(self.prev_token.span)
- .map_or(false, |snippet| snippet == "}")
+ .is_ok_and(|snippet| snippet == "}")
&& self.token.kind == token::Semi;
let mut semicolon_span = self.token.span;
if !is_unnecessary_semicolon {
@@ -795,11 +810,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and supertrait bounds.
let had_colon = self.eat(&token::Colon);
let span_at_colon = self.prev_token.span;
- let bounds = if had_colon {
- self.parse_generic_bounds(Some(self.prev_token.span))?
- } else {
- Vec::new()
- };
+ let bounds = if had_colon { self.parse_generic_bounds()? } else { Vec::new() };
let span_before_eq = self.prev_token.span;
if self.eat(&token::Eq) {
@@ -809,7 +820,7 @@ impl<'a> Parser<'a> {
self.sess.emit_err(errors::BoundsNotAllowedOnTraitAliases { span });
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
generics.where_clause = self.parse_where_clause()?;
self.expect_semi()?;
@@ -890,7 +901,7 @@ impl<'a> Parser<'a> {
// Parse optional colon and param bounds.
let bounds =
- if self.eat(&token::Colon) { self.parse_generic_bounds(None)? } else { Vec::new() };
+ if self.eat(&token::Colon) { self.parse_generic_bounds()? } else { Vec::new() };
let before_where_clause = self.parse_where_clause()?;
let ty = if self.eat(&token::Eq) { Some(self.parse_ty()?) } else { None };
@@ -963,15 +974,8 @@ impl<'a> Parser<'a> {
} 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();
+ self.sess
+ .emit_err(errors::SingleColonImportPath { span: self.prev_token.span });
// We parse the rest of the path and append it to the original prefix.
self.parse_path_segments(&mut prefix.segments, PathStyle::Mod, None)?;
@@ -1134,13 +1138,11 @@ impl<'a> Parser<'a> {
))
}
- fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &str) -> Option<T> {
+ fn error_bad_item_kind<T>(&self, span: Span, kind: &ItemKind, ctx: &'static str) -> Option<T> {
// FIXME(#100717): needs variant for each `ItemKind` (instead of using `ItemKind::descr()`)
let span = self.sess.source_map().guess_head_span(span);
let descr = kind.descr();
- self.struct_span_err(span, &format!("{descr} is not supported in {ctx}"))
- .help(&format!("consider moving the {descr} out to a nearby module scope"))
- .emit();
+ self.sess.emit_err(errors::BadItemKind { span, descr, ctx });
None
}
@@ -1282,6 +1284,7 @@ impl<'a> Parser<'a> {
}
}
+ let prev_span = self.prev_token.span;
let id = self.parse_ident()?;
let mut generics = self.parse_generics()?;
generics.where_clause = self.parse_where_clause()?;
@@ -1293,10 +1296,28 @@ impl<'a> Parser<'a> {
(thin_vec![], false)
} else {
self.parse_delim_comma_seq(Delimiter::Brace, |p| p.parse_enum_variant()).map_err(
- |mut e| {
- e.span_label(id.span, "while parsing this enum");
+ |mut err| {
+ err.span_label(id.span, "while parsing this enum");
+ if self.token == token::Colon {
+ let snapshot = self.create_snapshot_for_diagnostic();
+ self.bump();
+ match self.parse_ty() {
+ Ok(_) => {
+ err.span_suggestion_verbose(
+ prev_span,
+ "perhaps you meant to use `struct` here",
+ "struct".to_string(),
+ Applicability::MaybeIncorrect,
+ );
+ }
+ Err(e) => {
+ e.cancel();
+ }
+ }
+ self.restore_snapshot(snapshot);
+ }
self.recover_stmt();
- e
+ err
},
)?
};
@@ -1445,7 +1466,7 @@ impl<'a> Parser<'a> {
VariantData::Struct(fields, recovered)
} else {
let token_str = super::token_descr(&self.token);
- let msg = &format!("expected `where` or `{{` after union name, found {token_str}");
+ let msg = format!("expected `where` or `{{` after union name, found {token_str}");
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `where` or `{` after union name");
return Err(err);
@@ -1481,7 +1502,7 @@ impl<'a> Parser<'a> {
self.eat(&token::CloseDelim(Delimiter::Brace));
} else {
let token_str = super::token_descr(&self.token);
- let msg = &format!(
+ let msg = format!(
"expected {}`{{` after struct name, found {}",
if parsed_where { "" } else { "`where`, or " },
token_str
@@ -1618,7 +1639,7 @@ impl<'a> Parser<'a> {
let sp = self.prev_token.span.shrink_to_hi();
let mut err = self.struct_span_err(
sp,
- &format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
+ format!("expected `,`, or `}}`, found {}", super::token_descr(&self.token)),
);
// Try to recover extra trailing angle brackets
@@ -1713,27 +1734,13 @@ impl<'a> Parser<'a> {
self.expect_field_ty_separator()?;
let ty = self.parse_ty()?;
if self.token.kind == token::Colon && self.look_ahead(1, |tok| tok.kind != token::Colon) {
- self.struct_span_err(self.token.span, "found single colon in a struct field type path")
- .span_suggestion_verbose(
- self.token.span,
- "write a path separator here",
- "::",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::SingleColonStructType { span: self.token.span });
}
if self.token.kind == token::Eq {
self.bump();
let const_expr = self.parse_expr_anon_const()?;
let sp = ty.span.shrink_to_hi().to(const_expr.value.span);
- self.struct_span_err(sp, "default values on `struct` fields aren't supported")
- .span_suggestion(
- sp,
- "remove this unsupported default value",
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::EqualsStructDefault { span: sp });
}
Ok(FieldDef {
span: lo.to(self.prev_token.span),
@@ -1770,7 +1777,7 @@ impl<'a> Parser<'a> {
Ok(_) => {
let mut err = self.struct_span_err(
lo.to(self.prev_token.span),
- &format!("functions are not allowed in {adt_ty} definitions"),
+ format!("functions are not allowed in {adt_ty} definitions"),
);
err.help(
"unlike in C++, Java, and C#, functions are declared in `impl` blocks",
@@ -1789,7 +1796,7 @@ impl<'a> Parser<'a> {
Ok((ident, _)) => {
let mut err = self.struct_span_err(
lo.with_hi(ident.span.hi()),
- &format!("structs are not allowed in {adt_ty} definitions"),
+ format!("structs are not allowed in {adt_ty} definitions"),
);
err.help("consider creating a new `struct` definition instead of nesting");
err
@@ -1871,14 +1878,10 @@ impl<'a> Parser<'a> {
return IsMacroRulesItem::Yes { has_bang: true };
} else if self.look_ahead(1, |t| (t.is_ident())) {
// macro_rules foo
- self.struct_span_err(macro_rules_span, "expected `!` after `macro_rules`")
- .span_suggestion(
- macro_rules_span,
- "add a `!`",
- "macro_rules!",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::MacroRulesMissingBang {
+ span: macro_rules_span,
+ hi: macro_rules_span.shrink_to_hi(),
+ });
return IsMacroRulesItem::Yes { has_bang: false };
}
@@ -1903,9 +1906,7 @@ impl<'a> Parser<'a> {
if self.eat(&token::Not) {
// Handle macro_rules! foo!
let span = self.prev_token.span;
- self.struct_span_err(span, "macro names aren't followed by a `!`")
- .span_suggestion(span, "remove the `!`", "", Applicability::MachineApplicable)
- .emit();
+ self.sess.emit_err(errors::MacroNameRemoveBang { span });
}
let body = self.parse_delim_args()?;
@@ -1925,25 +1926,9 @@ impl<'a> Parser<'a> {
let vstr = pprust::vis_to_string(vis);
let vstr = vstr.trim_end();
if macro_rules {
- let msg = format!("can't qualify macro_rules invocation with `{vstr}`");
- self.struct_span_err(vis.span, &msg)
- .span_suggestion(
- vis.span,
- "try exporting the macro",
- "#[macro_export]",
- Applicability::MaybeIncorrect, // speculative
- )
- .emit();
+ self.sess.emit_err(errors::MacroRulesVisibility { span: vis.span, vis: vstr });
} else {
- self.struct_span_err(vis.span, "can't qualify macro invocation with `pub`")
- .span_suggestion(
- vis.span,
- "remove the visibility",
- "",
- Applicability::MachineApplicable,
- )
- .help(&format!("try adjusting the macro to put `{vstr}` inside the invocation"))
- .emit();
+ self.sess.emit_err(errors::MacroInvocationVisibility { span: vis.span, vis: vstr });
}
}
@@ -1989,18 +1974,12 @@ impl<'a> Parser<'a> {
let kw_token = self.token.clone();
let kw_str = pprust::token_to_string(&kw_token);
let item = self.parse_item(ForceCollect::No)?;
-
- self.struct_span_err(
- kw_token.span,
- &format!("`{kw_str}` definition cannot be nested inside `{keyword}`"),
- )
- .span_suggestion(
- item.unwrap().span,
- &format!("consider creating a new `{kw_str}` definition instead of nesting"),
- "",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::NestedAdt {
+ span: kw_token.span,
+ item: item.unwrap().span,
+ kw_str,
+ keyword: keyword.as_str(),
+ });
// We successfully parsed the item but we must inform the caller about nested problem.
return Ok(false);
}
@@ -2139,13 +2118,10 @@ impl<'a> Parser<'a> {
let _ = self.parse_expr()?;
self.expect_semi()?; // `;`
let span = eq_sp.to(self.prev_token.span);
- self.struct_span_err(span, "function body cannot be `= expression;`")
- .multipart_suggestion(
- "surround the expression with `{` and `}` instead of `=` and `;`",
- vec![(eq_sp, "{".to_string()), (self.prev_token.span, " }".to_string())],
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::FunctionBodyEqualsExpr {
+ span,
+ sugg: errors::FunctionBodyEqualsExprSugg { eq: eq_sp, semi: self.prev_token.span },
+ });
(AttrVec::new(), Some(self.mk_block_err(span)))
} else {
let expected = if req_body {
@@ -2289,11 +2265,11 @@ impl<'a> Parser<'a> {
err.span_suggestion(
self.token.uninterpolated_span(),
- &format!("`{original_kw}` already used earlier, remove this one"),
+ format!("`{original_kw}` already used earlier, remove this one"),
"",
Applicability::MachineApplicable,
)
- .span_note(original_sp, &format!("`{original_kw}` first seen here"));
+ .span_note(original_sp, format!("`{original_kw}` first seen here"));
}
// The keyword has not been seen yet, suggest correct placement in the function front matter
else if let Some(WrongKw::Misplaced(correct_pos_sp)) = wrong_kw {
@@ -2304,7 +2280,7 @@ impl<'a> Parser<'a> {
err.span_suggestion(
correct_pos_sp.to(misplaced_qual_sp),
- &format!("`{misplaced_qual}` must come before `{current_qual}`"),
+ format!("`{misplaced_qual}` must come before `{current_qual}`"),
format!("{misplaced_qual} {current_qual}"),
Applicability::MachineApplicable,
).note("keyword order for functions declaration is `pub`, `default`, `const`, `async`, `unsafe`, `extern`");
@@ -2328,7 +2304,7 @@ impl<'a> Parser<'a> {
if matches!(orig_vis.kind, VisibilityKind::Inherited) {
err.span_suggestion(
sp_start.to(self.prev_token.span),
- &format!("visibility `{vs}` must come before `{snippet}`"),
+ format!("visibility `{vs}` must come before `{snippet}`"),
format!("{vs} {snippet}"),
Applicability::MachineApplicable,
);
@@ -2577,14 +2553,12 @@ impl<'a> Parser<'a> {
}
fn recover_self_param(&mut self) -> bool {
- match self
- .parse_outer_attributes()
- .and_then(|_| self.parse_self_param())
- .map_err(|e| e.cancel())
- {
- Ok(Some(_)) => true,
- _ => false,
- }
+ matches!(
+ self.parse_outer_attributes()
+ .and_then(|_| self.parse_self_param())
+ .map_err(|e| e.cancel()),
+ Ok(Some(_))
+ )
}
}
diff --git a/compiler/rustc_parse/src/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs
index aa57b8047..c23420661 100644
--- a/compiler/rustc_parse/src/parser/mod.rs
+++ b/compiler/rustc_parse/src/parser/mod.rs
@@ -43,7 +43,7 @@ use thin_vec::ThinVec;
use tracing::debug;
use crate::errors::{
- IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
+ self, IncorrectVisibilityRestriction, MismatchedClosingDelimiter, NonStringAbiLiteral,
};
bitflags::bitflags! {
@@ -148,9 +148,6 @@ pub struct Parser<'a> {
max_angle_bracket_count: u32,
last_unexpected_token_span: Option<Span>,
- /// Span pointing at the `:` for the last type ascription the parser has seen, and whether it
- /// looked like it could have been a mistyped path or literal `Option:Some(42)`).
- pub last_type_ascription: Option<(Span, bool /* likely path typo */)>,
/// If present, this `Parser` is not parsing Rust code but rather a macro call.
subparser_name: Option<&'static str>,
capture_state: CaptureState,
@@ -165,7 +162,7 @@ pub struct Parser<'a> {
// This type is used a lot, e.g. it's cloned when matching many declarative macro rules with nonterminals. Make sure
// it doesn't unintentionally get bigger.
#[cfg(all(target_arch = "x86_64", target_pointer_width = "64"))]
-rustc_data_structures::static_assert_size!(Parser<'_>, 288);
+rustc_data_structures::static_assert_size!(Parser<'_>, 272);
/// Stores span information about a closure.
#[derive(Clone)]
@@ -470,7 +467,6 @@ impl<'a> Parser<'a> {
unmatched_angle_bracket_count: 0,
max_angle_bracket_count: 0,
last_unexpected_token_span: None,
- last_type_ascription: None,
subparser_name,
capture_state: CaptureState {
capturing: Capturing::No,
@@ -540,7 +536,9 @@ impl<'a> Parser<'a> {
} else if inedible.contains(&self.token.kind) {
// leave it in the input
Ok(false)
- } else if self.last_unexpected_token_span == Some(self.token.span) {
+ } else if self.token.kind != token::Eof
+ && self.last_unexpected_token_span == Some(self.token.span)
+ {
FatalError.raise();
} else {
self.expected_one_of_not_found(edible, inedible)
@@ -663,15 +661,10 @@ impl<'a> Parser<'a> {
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.sess.emit_err(errors::KwBadCase {
+ span: ident.span,
+ kw: kw.as_str()
+ });
self.bump();
return true;
}
@@ -914,7 +907,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_verbose(
self.prev_token.span.shrink_to_hi().until(self.token.span),
- &msg,
+ msg,
" @ ",
Applicability::MaybeIncorrect,
)
@@ -930,7 +923,7 @@ impl<'a> Parser<'a> {
expect_err
.span_suggestion_short(
sp,
- &format!("missing `{}`", token_str),
+ format!("missing `{}`", token_str),
token_str,
Applicability::MaybeIncorrect,
)
@@ -946,10 +939,14 @@ impl<'a> Parser<'a> {
// propagate the help message from sub error 'e' to main error 'expect_err;
expect_err.children.push(xx.clone());
}
- expect_err.emit();
-
e.cancel();
- break;
+ if self.token == token::Colon {
+ // we will try to recover in `maybe_recover_struct_lit_bad_delims`
+ return Err(expect_err);
+ } else {
+ expect_err.emit();
+ break;
+ }
}
}
}
diff --git a/compiler/rustc_parse/src/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs
index 7a4d53ed8..adb0d372a 100644
--- a/compiler/rustc_parse/src/parser/nonterminal.rs
+++ b/compiler/rustc_parse/src/parser/nonterminal.rs
@@ -20,12 +20,10 @@ impl<'a> Parser<'a> {
pub fn nonterminal_may_begin_with(kind: NonterminalKind, token: &Token) -> bool {
/// Checks whether the non-terminal may contain a single (non-keyword) identifier.
fn may_be_ident(nt: &token::Nonterminal) -> bool {
- match *nt {
- token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_) => {
- false
- }
- _ => true,
- }
+ !matches!(
+ *nt,
+ token::NtItem(_) | token::NtBlock(_) | token::NtVis(_) | token::NtLifetime(_)
+ )
}
match kind {
diff --git a/compiler/rustc_parse/src/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs
index 2246002f5..c317d9636 100644
--- a/compiler/rustc_parse/src/parser/pat.rs
+++ b/compiler/rustc_parse/src/parser/pat.rs
@@ -1,6 +1,6 @@
use super::{ForceCollect, Parser, PathStyle, TrailingToken};
use crate::errors::{
- AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
+ self, AmbiguousRangePattern, DotDotDotForRemainingFields, DotDotDotRangeToPatternNotAllowed,
DotDotDotRestPattern, EnumPatternInsteadOfIdentifier, ExpectedBindingLeftOfAt,
ExpectedCommaAfterPatternField, InclusiveRangeExtraEquals, InclusiveRangeMatchArrow,
InclusiveRangeNoEnd, InvalidMutInPattern, PatternOnWrongSideOfAt, RefMutOrderIncorrect,
@@ -406,11 +406,11 @@ impl<'a> Parser<'a> {
// Parse pattern starting with a path
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let (qself, path) = self.parse_qpath(PathStyle::Pat)?;
(Some(qself), path)
} else {
// Parse an unqualified path
- (None, self.parse_path(PathStyle::Expr)?)
+ (None, self.parse_path(PathStyle::Pat)?)
};
let span = lo.to(self.prev_token.span);
@@ -444,7 +444,7 @@ impl<'a> Parser<'a> {
super::token_descr(&self_.token)
);
- let mut err = self_.struct_span_err(self_.token.span, &msg);
+ let mut err = self_.struct_span_err(self_.token.span, msg);
err.span_label(self_.token.span, format!("expected {}", expected));
err
});
@@ -666,7 +666,7 @@ impl<'a> Parser<'a> {
fn parse_pat_mac_invoc(&mut self, path: Path) -> PResult<'a, PatKind> {
self.bump();
let args = self.parse_delim_args()?;
- let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
+ let mac = P(MacCall { path, args });
Ok(PatKind::MacCall(mac))
}
@@ -680,7 +680,7 @@ impl<'a> Parser<'a> {
let expected = Expected::to_string_or_fallback(expected);
let msg = format!("expected {}, found {}", expected, super::token_descr(&self.token));
- let mut err = self.struct_span_err(self.token.span, &msg);
+ let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, format!("expected {}", expected));
let sp = self.sess.source_map().start_point(self.token.span);
@@ -789,11 +789,11 @@ impl<'a> Parser<'a> {
let lo = self.token.span;
let (qself, path) = if self.eat_lt() {
// Parse a qualified path
- let (qself, path) = self.parse_qpath(PathStyle::Expr)?;
+ let (qself, path) = self.parse_qpath(PathStyle::Pat)?;
(Some(qself), path)
} else {
// Parse an unqualified path
- (None, self.parse_path(PathStyle::Expr)?)
+ (None, self.parse_path(PathStyle::Pat)?)
};
let hi = self.prev_token.span;
Ok(self.mk_expr(lo.to(hi), ExprKind::Path(qself, path)))
@@ -908,18 +908,13 @@ impl<'a> Parser<'a> {
let box_span = self.prev_token.span;
if self.isnt_pattern_start() {
- self.struct_span_err(
- self.token.span,
- format!("expected pattern, found {}", super::token_descr(&self.token)),
- )
- .span_note(box_span, "`box` is a reserved keyword")
- .span_suggestion_verbose(
- box_span.shrink_to_lo(),
- "escape `box` to use it as an identifier",
- "r#",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ let descr = super::token_descr(&self.token);
+ self.sess.emit_err(errors::BoxNotPat {
+ span: self.token.span,
+ kw: box_span,
+ lo: box_span.shrink_to_lo(),
+ descr,
+ });
// We cannot use `parse_pat_ident()` since it will complain `box`
// is not an identifier.
@@ -983,7 +978,7 @@ impl<'a> Parser<'a> {
break;
}
let token_str = super::token_descr(&self.token);
- let msg = &format!("expected `}}`, found {}", token_str);
+ let msg = format!("expected `}}`, found {}", token_str);
let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected `}`");
diff --git a/compiler/rustc_parse/src/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs
index c25c23d84..feb7e829c 100644
--- a/compiler/rustc_parse/src/parser/path.rs
+++ b/compiler/rustc_parse/src/parser/path.rs
@@ -1,5 +1,6 @@
use super::ty::{AllowPlus, RecoverQPath, RecoverReturnSign};
use super::{Parser, Restrictions, TokenType};
+use crate::errors::PathSingleColon;
use crate::{errors, maybe_whole};
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, Token, TokenKind};
@@ -8,7 +9,7 @@ use rustc_ast::{
AssocConstraintKind, BlockCheckMode, GenericArg, GenericArgs, Generics, ParenthesizedArgs,
Path, PathSegment, QSelf,
};
-use rustc_errors::{pluralize, Applicability, PResult};
+use rustc_errors::{Applicability, IntoDiagnostic, PResult};
use rustc_span::source_map::{BytePos, Span};
use rustc_span::symbol::{kw, sym, Ident};
use std::mem;
@@ -24,7 +25,19 @@ pub enum PathStyle {
/// In all such contexts the non-path interpretation is preferred by default for practical
/// reasons, but the path interpretation can be forced by the disambiguator `::`, e.g.
/// `x<y>` - comparisons, `x::<y>` - unambiguously a path.
+ ///
+ /// Also, a path may never be followed by a `:`. This means that we can eagerly recover if
+ /// we encounter it.
Expr,
+ /// The same as `Expr`, but may be followed by a `:`.
+ /// For example, this code:
+ /// ```rust
+ /// struct S;
+ ///
+ /// let S: S;
+ /// // ^ Followed by a `:`
+ /// ```
+ Pat,
/// In other contexts, notably in types, no ambiguity exists and paths can be written
/// without the disambiguator, e.g., `x<y>` - unambiguously a path.
/// Paths with disambiguators are still accepted, `x::<Y>` - unambiguously a path too.
@@ -38,6 +51,12 @@ pub enum PathStyle {
Mod,
}
+impl PathStyle {
+ fn has_generic_ambiguity(&self) -> bool {
+ matches!(self, Self::Expr | Self::Pat)
+ }
+}
+
impl<'a> Parser<'a> {
/// Parses a qualified path.
/// Assumes that the leading `<` has been parsed already.
@@ -150,16 +169,13 @@ impl<'a> Parser<'a> {
//
if style == PathStyle::Mod && path.segments.iter().any(|segment| segment.args.is_some())
{
- parser
- .struct_span_err(
- path.segments
- .iter()
- .filter_map(|segment| segment.args.as_ref())
- .map(|arg| arg.span())
- .collect::<Vec<_>>(),
- "unexpected generic arguments in path",
- )
- .emit();
+ let span = path
+ .segments
+ .iter()
+ .filter_map(|segment| segment.args.as_ref())
+ .map(|arg| arg.span())
+ .collect::<Vec<_>>();
+ parser.sess.emit_err(errors::GenericsInPath { span });
}
};
@@ -186,7 +202,6 @@ impl<'a> Parser<'a> {
segments.push(PathSegment::path_root(lo.shrink_to_lo().with_ctxt(mod_sep_ctxt)));
}
self.parse_path_segments(&mut segments, style, ty_generics)?;
-
Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None })
}
@@ -198,7 +213,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, ()> {
loop {
let segment = self.parse_path_segment(style, ty_generics)?;
- if style == PathStyle::Expr {
+ if style.has_generic_ambiguity() {
// In order to check for trailing angle brackets, we must have finished
// recursing (`parse_path_segment` can indirectly call this function),
// that is, the next token must be the highlighted part of the below example:
@@ -220,6 +235,29 @@ impl<'a> Parser<'a> {
segments.push(segment);
if self.is_import_coupler() || !self.eat(&token::ModSep) {
+ if style == PathStyle::Expr
+ && self.may_recover()
+ && self.token == token::Colon
+ && self.look_ahead(1, |token| token.is_ident() && !token.is_reserved_ident())
+ {
+ // Emit a special error message for `a::b:c` to help users
+ // otherwise, `a: c` might have meant to introduce a new binding
+ if self.token.span.lo() == self.prev_token.span.hi()
+ && self.look_ahead(1, |token| self.token.span.hi() == token.span.lo())
+ {
+ self.bump(); // bump past the colon
+ self.sess.emit_err(PathSingleColon {
+ span: self.prev_token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ });
+ }
+ continue;
+ }
+
return Ok(());
}
}
@@ -273,8 +311,25 @@ impl<'a> Parser<'a> {
ty_generics,
)?;
self.expect_gt().map_err(|mut err| {
+ // Try to recover a `:` into a `::`
+ if self.token == token::Colon
+ && self.look_ahead(1, |token| {
+ token.is_ident() && !token.is_reserved_ident()
+ })
+ {
+ err.cancel();
+ err = PathSingleColon {
+ span: self.token.span,
+ type_ascription: self
+ .sess
+ .unstable_features
+ .is_nightly_build()
+ .then_some(()),
+ }
+ .into_diagnostic(self.diagnostic());
+ }
// Attempt to find places where a missing `>` might belong.
- if let Some(arg) = args
+ else if let Some(arg) = args
.iter()
.rev()
.find(|arg| !matches!(arg, AngleBracketedArg::Constraint(_)))
@@ -467,23 +522,10 @@ impl<'a> Parser<'a> {
// i.e. no multibyte characters, in this range.
let span =
lo.with_hi(lo.lo() + BytePos(snapshot.unmatched_angle_bracket_count));
- self.struct_span_err(
+ self.sess.emit_err(errors::UnmatchedAngle {
span,
- &format!(
- "unmatched angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- )
- .span_suggestion(
- span,
- &format!(
- "remove extra angle bracket{}",
- pluralize!(snapshot.unmatched_angle_bracket_count)
- ),
- "",
- Applicability::MachineApplicable,
- )
- .emit();
+ plural: snapshot.unmatched_angle_bracket_count > 1,
+ });
// Try again without unmatched angle bracket characters.
self.parse_angle_args(ty_generics)
@@ -564,7 +606,7 @@ impl<'a> Parser<'a> {
let kind = if self.eat(&token::Colon) {
// Parse associated type constraint bound.
- let bounds = self.parse_generic_bounds(Some(self.prev_token.span))?;
+ let bounds = self.parse_generic_bounds()?;
AssocConstraintKind::Bound { bounds }
} else if self.eat(&token::Eq) {
self.parse_assoc_equality_term(ident, self.prev_token.span)?
@@ -620,10 +662,7 @@ impl<'a> Parser<'a> {
c.into()
}
Some(GenericArg::Lifetime(lt)) => {
- self.struct_span_err(span, "associated lifetimes are not supported")
- .span_label(lt.ident.span, "the lifetime is given here")
- .help("if you meant to specify a trait object, write `dyn Trait + 'lifetime`")
- .emit();
+ self.sess.emit_err(errors::AssocLifetime { span, lifetime: lt.ident.span });
self.mk_ty(span, ast::TyKind::Err).into()
}
None => {
@@ -640,14 +679,14 @@ impl<'a> Parser<'a> {
);
err.span_suggestion(
eq.to(before_next),
- &format!("remove the `=` if `{}` is a type", ident),
+ format!("remove the `=` if `{}` is a type", ident),
"",
Applicability::MaybeIncorrect,
)
} else {
err.span_label(
self.token.span,
- &format!("expected type, found {}", super::token_descr(&self.token)),
+ format!("expected type, found {}", super::token_descr(&self.token)),
)
};
return Err(err);
diff --git a/compiler/rustc_parse/src/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs
index fbe5b88c4..54f9fc5d2 100644
--- a/compiler/rustc_parse/src/parser/stmt.rs
+++ b/compiler/rustc_parse/src/parser/stmt.rs
@@ -10,6 +10,8 @@ use super::{
use crate::errors;
use crate::maybe_whole;
+use crate::errors::MalformedLoopLabel;
+use ast::Label;
use rustc_ast as ast;
use rustc_ast::ptr::P;
use rustc_ast::token::{self, Delimiter, TokenKind};
@@ -19,7 +21,8 @@ use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, HasAttrs, Local, Stmt};
use rustc_ast::{StmtKind, DUMMY_NODE_ID};
use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed, PResult};
use rustc_span::source_map::{BytePos, Span};
-use rustc_span::symbol::{kw, sym};
+use rustc_span::symbol::{kw, sym, Ident};
+
use std::mem;
use thin_vec::{thin_vec, ThinVec};
@@ -37,7 +40,8 @@ impl<'a> Parser<'a> {
/// If `force_collect` is [`ForceCollect::Yes`], forces collection of tokens regardless of whether
/// or not we have attributes
- pub(crate) fn parse_stmt_without_recovery(
+ // Public for `cfg_eval` macro expansion.
+ pub fn parse_stmt_without_recovery(
&mut self,
capture_semi: bool,
force_collect: ForceCollect,
@@ -87,7 +91,11 @@ impl<'a> Parser<'a> {
attrs,
errors::InvalidVariableDeclarationSub::UseLetNotVar,
)?
- } else if self.check_path() && !self.token.is_qpath_start() && !self.is_path_start_item() {
+ } else if self.check_path()
+ && !self.token.is_qpath_start()
+ && !self.is_path_start_item()
+ && !self.is_builtin()
+ {
// We have avoided contextual keywords like `union`, items with `crate` visibility,
// or `auto trait` items. We aim to parse an arbitrary path `a::b` but not something
// that starts like a path (1 token), but it fact not a path.
@@ -96,7 +104,13 @@ impl<'a> Parser<'a> {
ForceCollect::Yes => {
self.collect_tokens_no_attrs(|this| this.parse_stmt_path_start(lo, attrs))?
}
- ForceCollect::No => self.parse_stmt_path_start(lo, attrs)?,
+ ForceCollect::No => match self.parse_stmt_path_start(lo, attrs) {
+ Ok(stmt) => stmt,
+ Err(mut err) => {
+ self.suggest_add_missing_let_for_stmt(&mut err);
+ return Err(err);
+ }
+ },
}
} else if let Some(item) = self.parse_item_common(
attrs.clone(),
@@ -186,7 +200,7 @@ impl<'a> Parser<'a> {
_ => MacStmtStyle::NoBraces,
};
- let mac = P(MacCall { path, args, prior_type_ascription: self.last_type_ascription });
+ let mac = P(MacCall { path, args });
let kind = if (style == MacStmtStyle::Braces
&& self.token != token::Dot
@@ -546,10 +560,27 @@ impl<'a> Parser<'a> {
}
let stmt = match self.parse_full_stmt(recover) {
Err(mut err) if recover.yes() => {
- self.maybe_annotate_with_ascription(&mut err, false);
if let Some(ref mut snapshot) = snapshot {
snapshot.recover_diff_marker();
}
+ if self.token == token::Colon {
+ // if next token is following a colon, it's likely a path
+ // and we can suggest a path separator
+ self.bump();
+ if self.token.span.lo() == self.prev_token.span.hi() {
+ err.span_suggestion_verbose(
+ self.prev_token.span,
+ "maybe write a path separator here",
+ "::",
+ Applicability::MaybeIncorrect,
+ );
+ }
+ if self.sess.unstable_features.is_nightly_build() {
+ // FIXME(Nilstrieb): Remove this again after a few months.
+ err.note("type ascription syntax has been removed, see issue #101728 <https://github.com/rust-lang/rust/issues/101728>");
+ }
+ }
+
err.emit();
self.recover_stmt_(SemiColonMode::Ignore, BlockMode::Ignore);
Some(self.mk_stmt_err(self.token.span))
@@ -580,47 +611,104 @@ impl<'a> Parser<'a> {
};
let mut eat_semi = true;
+ let mut add_semi_to_stmt = false;
+
match &mut stmt.kind {
// Expression without semicolon.
StmtKind::Expr(expr)
if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => {
// Just check for errors and recover; do not eat semicolon yet.
// `expect_one_of` returns PResult<'a, bool /* recovered */>
- let replace_with_err =
- match self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]) {
+
+ let expect_result = self.expect_one_of(&[], &[token::Semi, token::CloseDelim(Delimiter::Brace)]);
+
+ let replace_with_err = 'break_recover: {
+ match expect_result {
// Recover from parser, skip type error to avoid extra errors.
- Ok(true) => true,
- Err(mut e) => {
- if let TokenKind::DocComment(..) = self.token.kind &&
- let Ok(snippet) = self.span_to_snippet(self.token.span) {
+ Ok(true) => true,
+ Err(mut e) => {
+ if let TokenKind::DocComment(..) = self.token.kind
+ && let Ok(snippet) = self.span_to_snippet(self.token.span)
+ {
let sp = self.token.span;
let marker = &snippet[..3];
let (comment_marker, doc_comment_marker) = marker.split_at(2);
e.span_suggestion(
sp.with_hi(sp.lo() + BytePos(marker.len() as u32)),
- &format!(
+ format!(
"add a space before `{}` to use a regular comment",
doc_comment_marker,
),
format!("{} {}", comment_marker, doc_comment_marker),
Applicability::MaybeIncorrect,
);
- }
+ }
+
+ if self.recover_colon_as_semi() {
+ // recover_colon_as_semi has already emitted a nicer error.
+ e.delay_as_bug();
+ add_semi_to_stmt = true;
+ eat_semi = false;
- if let Err(mut e) =
- self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
- {
- if recover.no() {
- return Err(e);
+ break 'break_recover false;
}
- e.emit();
- self.recover_stmt();
+
+ match &expr.kind {
+ ExprKind::Path(None, ast::Path { segments, .. }) if segments.len() == 1 => {
+ if self.token == token::Colon
+ && self.look_ahead(1, |token| {
+ token.is_whole_block() || matches!(
+ token.kind,
+ token::Ident(kw::For | kw::Loop | kw::While, false)
+ | token::OpenDelim(Delimiter::Brace)
+ )
+ })
+ {
+ let snapshot = self.create_snapshot_for_diagnostic();
+ let label = Label {
+ ident: Ident::from_str_and_span(
+ &format!("'{}", segments[0].ident),
+ segments[0].ident.span,
+ ),
+ };
+ match self.parse_expr_labeled(label, false) {
+ Ok(labeled_expr) => {
+ e.delay_as_bug();
+ self.sess.emit_err(MalformedLoopLabel {
+ span: label.ident.span,
+ correct_label: label.ident,
+ });
+ *expr = labeled_expr;
+ break 'break_recover false;
+ }
+ Err(err) => {
+ err.cancel();
+ self.restore_snapshot(snapshot);
+ }
+ }
+ }
+ }
+ _ => {}
+ }
+
+ if let Err(mut e) =
+ self.check_mistyped_turbofish_with_multiple_type_params(e, expr)
+ {
+ if recover.no() {
+ return Err(e);
+ }
+ e.emit();
+ self.recover_stmt();
+ }
+
+ true
+
}
- true
+ Ok(false) => false
}
- _ => false
};
+
if replace_with_err {
// We already emitted an error, so don't emit another type error
let sp = expr.span.to(self.prev_token.span);
@@ -643,9 +731,10 @@ impl<'a> Parser<'a> {
StmtKind::Empty | StmtKind::Item(_) | StmtKind::Local(_) | StmtKind::Semi(_) => eat_semi = false,
}
- if eat_semi && self.eat(&token::Semi) {
+ if add_semi_to_stmt || (eat_semi && self.eat(&token::Semi)) {
stmt = stmt.add_trailing_semicolon();
}
+
stmt.span = stmt.span.to(self.prev_token.span);
Ok(Some(stmt))
}
diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs
index 400c8dbe9..a29b696ae 100644
--- a/compiler/rustc_parse/src/parser/ty.rs
+++ b/compiler/rustc_parse/src/parser/ty.rs
@@ -1,10 +1,9 @@
use super::{Parser, PathStyle, TokenType};
use crate::errors::{
- DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
+ self, DynAfterMut, ExpectedFnPathFoundFnKeyword, ExpectedMutOrConstInRawPointerType,
FnPointerCannotBeAsync, FnPointerCannotBeConst, FnPtrWithGenerics, FnPtrWithGenericsSugg,
- InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime,
- NegativeBoundsNotSupported, NegativeBoundsNotSupportedSugg, NestedCVariadicType,
+ InvalidDynKeyword, LifetimeAfterMut, NeedPlusAfterTraitObjectLifetime, NestedCVariadicType,
ReturnTypesUseThinArrow,
};
use crate::{maybe_recover_from_interpolated_ty_qpath, maybe_whole};
@@ -14,8 +13,9 @@ 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,
+ self as ast, BareFnTy, BoundPolarity, FnRetTy, GenericBound, GenericBounds, GenericParam,
+ Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, TraitBoundModifier,
+ TraitObjectSyntax, Ty, TyKind,
};
use rustc_errors::{Applicability, PResult};
use rustc_span::source_map::Span;
@@ -23,10 +23,10 @@ use rustc_span::symbol::{kw, sym, Ident};
use rustc_span::Symbol;
use thin_vec::{thin_vec, ThinVec};
-/// Any `?` or `~const` modifiers that appear at the start of a bound.
+/// Any `?`, `!`, or `~const` modifiers that appear at the start of a bound.
struct BoundModifiers {
/// `?Trait`.
- maybe: Option<Span>,
+ bound_polarity: BoundPolarity,
/// `~const Trait`.
maybe_const: Option<Span>,
@@ -34,11 +34,13 @@ struct BoundModifiers {
impl BoundModifiers {
fn to_trait_bound_modifier(&self) -> TraitBoundModifier {
- match (self.maybe, self.maybe_const) {
- (None, None) => TraitBoundModifier::None,
- (Some(_), None) => TraitBoundModifier::Maybe,
- (None, Some(_)) => TraitBoundModifier::MaybeConst,
- (Some(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
+ match (self.bound_polarity, self.maybe_const) {
+ (BoundPolarity::Positive, None) => TraitBoundModifier::None,
+ (BoundPolarity::Negative(_), None) => TraitBoundModifier::Negative,
+ (BoundPolarity::Maybe(_), None) => TraitBoundModifier::Maybe,
+ (BoundPolarity::Positive, Some(_)) => TraitBoundModifier::MaybeConst,
+ (BoundPolarity::Negative(_), Some(_)) => TraitBoundModifier::MaybeConstNegative,
+ (BoundPolarity::Maybe(_), Some(_)) => TraitBoundModifier::MaybeConstMaybe,
}
}
}
@@ -315,9 +317,8 @@ impl<'a> Parser<'a> {
}
} else {
let msg = format!("expected type, found {}", super::token_descr(&self.token));
- let mut err = self.struct_span_err(self.token.span, &msg);
+ let mut err = self.struct_span_err(self.token.span, msg);
err.span_label(self.token.span, "expected type");
- self.maybe_annotate_with_ascription(&mut err, true);
return Err(err);
};
@@ -369,7 +370,7 @@ impl<'a> Parser<'a> {
fn parse_bare_trait_object(&mut self, lo: Span, allow_plus: AllowPlus) -> PResult<'a, TyKind> {
let lt_no_plus = self.check_lifetime() && !self.look_ahead(1, |t| t.is_like_plus());
- let bounds = self.parse_generic_bounds_common(allow_plus, None)?;
+ let bounds = self.parse_generic_bounds_common(allow_plus)?;
if lt_no_plus {
self.sess.emit_err(NeedPlusAfterTraitObjectLifetime { span: lo });
}
@@ -396,7 +397,7 @@ impl<'a> Parser<'a> {
) -> PResult<'a, TyKind> {
if plus {
self.eat_plus(); // `+`, or `+=` gets split and `+` is discarded
- bounds.append(&mut self.parse_generic_bounds(Some(self.prev_token.span))?);
+ bounds.append(&mut self.parse_generic_bounds()?);
}
Ok(TyKind::TraitObject(bounds, TraitObjectSyntax::None))
}
@@ -588,24 +589,18 @@ impl<'a> Parser<'a> {
// Always parse bounds greedily for better error recovery.
if self.token.is_lifetime() {
self.look_ahead(1, |t| {
- if let token::Ident(symname, _) = t.kind {
+ if let token::Ident(sym, _) = t.kind {
// parse pattern with "'a Sized" we're supposed to give suggestion like
// "'a + Sized"
- self.struct_span_err(
- self.token.span,
- &format!("expected `+` between lifetime and {}", symname),
- )
- .span_suggestion_verbose(
- self.token.span.shrink_to_hi(),
- "add `+`",
- " +",
- Applicability::MaybeIncorrect,
- )
- .emit();
+ self.sess.emit_err(errors::MissingPlusBounds {
+ span: self.token.span,
+ hi: self.token.span.shrink_to_hi(),
+ sym,
+ });
}
})
}
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::ImplTrait(ast::DUMMY_NODE_ID, bounds))
}
@@ -636,7 +631,7 @@ impl<'a> Parser<'a> {
};
// Always parse bounds greedily for better error recovery.
- let bounds = self.parse_generic_bounds(None)?;
+ let bounds = self.parse_generic_bounds()?;
*impl_dyn_multi = bounds.len() > 1 || self.prev_token.kind == TokenKind::BinOp(token::Plus);
Ok(TyKind::TraitObject(bounds, syntax))
}
@@ -657,11 +652,7 @@ impl<'a> Parser<'a> {
let path = self.parse_path_inner(PathStyle::Type, ty_generics)?;
if self.eat(&token::Not) {
// Macro invocation in type position
- Ok(TyKind::MacCall(P(MacCall {
- path,
- args: self.parse_delim_args()?,
- prior_type_ascription: self.last_type_ascription,
- })))
+ Ok(TyKind::MacCall(P(MacCall { path, args: self.parse_delim_args()? })))
} else if allow_plus == AllowPlus::Yes && self.check_plus() {
// `Trait1 + Trait2 + 'a`
self.parse_remaining_bounds_path(ThinVec::new(), path, lo, true)
@@ -671,23 +662,15 @@ impl<'a> Parser<'a> {
}
}
- pub(super) fn parse_generic_bounds(
- &mut self,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
- self.parse_generic_bounds_common(AllowPlus::Yes, colon_span)
+ pub(super) fn parse_generic_bounds(&mut self) -> PResult<'a, GenericBounds> {
+ self.parse_generic_bounds_common(AllowPlus::Yes)
}
/// Parses bounds of a type parameter `BOUND + BOUND + ...`, possibly with trailing `+`.
///
/// See `parse_generic_bound` for the `BOUND` grammar.
- fn parse_generic_bounds_common(
- &mut self,
- allow_plus: AllowPlus,
- colon_span: Option<Span>,
- ) -> PResult<'a, GenericBounds> {
+ fn parse_generic_bounds_common(&mut self, allow_plus: AllowPlus) -> PResult<'a, GenericBounds> {
let mut bounds = Vec::new();
- let mut negative_bounds = Vec::new();
// In addition to looping while we find generic bounds:
// We continue even if we find a keyword. This is necessary for error recovery on,
@@ -704,19 +687,12 @@ impl<'a> Parser<'a> {
self.sess.emit_err(InvalidDynKeyword { span: self.token.span });
self.bump();
}
- match self.parse_generic_bound()? {
- Ok(bound) => bounds.push(bound),
- Err(neg_sp) => negative_bounds.push(neg_sp),
- }
+ bounds.push(self.parse_generic_bound()?);
if allow_plus == AllowPlus::No || !self.eat_plus() {
break;
}
}
- if !negative_bounds.is_empty() {
- self.error_negative_bounds(colon_span, &bounds, negative_bounds);
- }
-
Ok(bounds)
}
@@ -724,55 +700,22 @@ impl<'a> Parser<'a> {
fn can_begin_bound(&mut self) -> bool {
// This needs to be synchronized with `TokenKind::can_begin_bound`.
self.check_path()
- || self.check_lifetime()
- || self.check(&token::Not) // Used for error reporting only.
- || self.check(&token::Question)
- || self.check(&token::Tilde)
- || self.check_keyword(kw::For)
- || self.check(&token::OpenDelim(Delimiter::Parenthesis))
- }
-
- fn error_negative_bounds(
- &self,
- colon_span: Option<Span>,
- bounds: &[GenericBound],
- negative_bounds: Vec<Span>,
- ) {
- let sub = if let Some(bound_list) = colon_span {
- let bound_list = bound_list.to(self.prev_token.span);
- let mut new_bound_list = String::new();
- if !bounds.is_empty() {
- let mut snippets = bounds.iter().map(|bound| self.span_to_snippet(bound.span()));
- while let Some(Ok(snippet)) = snippets.next() {
- new_bound_list.push_str(" + ");
- new_bound_list.push_str(&snippet);
- }
- new_bound_list = new_bound_list.replacen(" +", ":", 1);
- }
-
- Some(NegativeBoundsNotSupportedSugg {
- bound_list,
- num_bounds: negative_bounds.len(),
- fixed: new_bound_list,
- })
- } else {
- None
- };
-
- let last_span = *negative_bounds.last().expect("no negative bounds, but still error?");
- self.sess.emit_err(NegativeBoundsNotSupported { negative_bounds, last_span, sub });
+ || self.check_lifetime()
+ || self.check(&token::Not)
+ || self.check(&token::Question)
+ || self.check(&token::Tilde)
+ || self.check_keyword(kw::For)
+ || self.check(&token::OpenDelim(Delimiter::Parenthesis))
}
/// Parses a bound according to the grammar:
/// ```ebnf
/// BOUND = TY_BOUND | LT_BOUND
/// ```
- fn parse_generic_bound(&mut self) -> PResult<'a, Result<GenericBound, Span>> {
- let anchor_lo = self.prev_token.span;
+ fn parse_generic_bound(&mut self) -> PResult<'a, GenericBound> {
let lo = self.token.span;
let has_parens = self.eat(&token::OpenDelim(Delimiter::Parenthesis));
let inner_lo = self.token.span;
- let is_negative = self.eat(&token::Not);
let modifiers = self.parse_ty_bound_modifiers()?;
let bound = if self.token.is_lifetime() {
@@ -782,7 +725,7 @@ impl<'a> Parser<'a> {
self.parse_generic_ty_bound(lo, has_parens, modifiers)?
};
- Ok(if is_negative { Err(anchor_lo.to(self.prev_token.span)) } else { Ok(bound) })
+ Ok(bound)
}
/// Parses a lifetime ("outlives") bound, e.g. `'a`, according to:
@@ -807,16 +750,17 @@ impl<'a> Parser<'a> {
/// Emits an error if any trait bound modifiers were present.
fn error_lt_bound_with_modifiers(&self, modifiers: BoundModifiers) {
if let Some(span) = modifiers.maybe_const {
- self.struct_span_err(
- span,
- "`~const` may only modify trait bounds, not lifetime bounds",
- )
- .emit();
+ self.sess.emit_err(errors::TildeConstLifetime { span });
}
- if let Some(span) = modifiers.maybe {
- self.struct_span_err(span, "`?` may only modify trait bounds, not lifetime bounds")
- .emit();
+ match modifiers.bound_polarity {
+ BoundPolarity::Positive => {}
+ BoundPolarity::Negative(span) => {
+ self.sess.emit_err(errors::ModifierLifetime { span, sigil: "!" });
+ }
+ BoundPolarity::Maybe(span) => {
+ self.sess.emit_err(errors::ModifierLifetime { span, sigil: "?" });
+ }
}
}
@@ -824,19 +768,14 @@ impl<'a> Parser<'a> {
fn recover_paren_lifetime(&mut self, lo: Span, inner_lo: Span) -> PResult<'a, ()> {
let inner_span = inner_lo.to(self.prev_token.span);
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
- let mut err = self.struct_span_err(
- lo.to(self.prev_token.span),
- "parenthesized lifetime bounds are not supported",
- );
- if let Ok(snippet) = self.span_to_snippet(inner_span) {
- err.span_suggestion_short(
- lo.to(self.prev_token.span),
- "remove the parentheses",
- snippet,
- Applicability::MachineApplicable,
- );
- }
- err.emit();
+ let span = lo.to(self.prev_token.span);
+ let (sugg, snippet) = if let Ok(snippet) = self.span_to_snippet(inner_span) {
+ (Some(span), snippet)
+ } else {
+ (None, String::new())
+ };
+
+ self.sess.emit_err(errors::ParenthesizedLifetime { span, sugg, snippet });
Ok(())
}
@@ -857,24 +796,23 @@ impl<'a> Parser<'a> {
} else if self.eat_keyword(kw::Const) {
let span = self.prev_token.span;
self.sess.gated_spans.gate(sym::const_trait_impl, span);
-
- self.struct_span_err(span, "const bounds must start with `~`")
- .span_suggestion(
- span.shrink_to_lo(),
- "add `~`",
- "~",
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::ConstMissingTilde { span, start: span.shrink_to_lo() });
Some(span)
} else {
None
};
- let maybe = self.eat(&token::Question).then_some(self.prev_token.span);
+ let bound_polarity = if self.eat(&token::Question) {
+ BoundPolarity::Maybe(self.prev_token.span)
+ } else if self.eat(&token::Not) {
+ self.sess.gated_spans.gate(sym::negative_bounds, self.prev_token.span);
+ BoundPolarity::Negative(self.prev_token.span)
+ } else {
+ BoundPolarity::Positive
+ };
- Ok(BoundModifiers { maybe, maybe_const })
+ Ok(BoundModifiers { bound_polarity, maybe_const })
}
/// Parses a type bound according to:
@@ -944,14 +882,10 @@ impl<'a> Parser<'a> {
self.parse_remaining_bounds(bounds, true)?;
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
let sp = vec![lo, self.prev_token.span];
- let sugg = vec![(lo, String::from(" ")), (self.prev_token.span, String::new())];
- self.struct_span_err(sp, "incorrect braces around trait bounds")
- .multipart_suggestion(
- "remove the parentheses",
- sugg,
- Applicability::MachineApplicable,
- )
- .emit();
+ self.sess.emit_err(errors::IncorrectBracesTraitBounds {
+ span: sp,
+ sugg: errors::IncorrectBracesTraitBoundsSugg { l: lo, r: self.prev_token.span },
+ });
} else {
self.expect(&token::CloseDelim(Delimiter::Parenthesis))?;
}
diff --git a/compiler/rustc_parse/src/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs
index 72402a200..928fdce31 100644
--- a/compiler/rustc_parse/src/validate_attr.rs
+++ b/compiler/rustc_parse/src/validate_attr.rs
@@ -1,6 +1,6 @@
//! Meta-syntax validation logic of attributes for post-expansion.
-use crate::parse_in;
+use crate::{errors, parse_in};
use rustc_ast::tokenstream::DelimSpan;
use rustc_ast::MetaItemKind;
@@ -45,7 +45,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
kind: match &item.args {
AttrArgs::Empty => MetaItemKind::Word,
AttrArgs::Delimited(DelimArgs { dspan, delim, tokens }) => {
- check_meta_bad_delim(sess, *dspan, *delim, "wrong meta list delimiters");
+ check_meta_bad_delim(sess, *dspan, *delim);
let nmis = parse_in(sess, tokens.clone(), "meta list", |p| p.parse_meta_seq_top())?;
MetaItemKind::List(nmis)
}
@@ -68,7 +68,7 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
}
} else {
// The non-error case can happen with e.g. `#[foo = 1+1]`. The error case can
- // happen with e.g. `#[foo = include_str!("non-existent-file.rs")]`; in that
+ // happen with e.g. `#[foo = include_str!("nonexistent-file.rs")]`; in that
// case we delay the error because an earlier error will have already been
// reported.
let msg = format!("unexpected expression: `{}`", pprust::expr_to_string(expr));
@@ -84,19 +84,24 @@ pub fn parse_meta<'a>(sess: &'a ParseSess, attr: &Attribute) -> PResult<'a, Meta
})
}
-pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter, msg: &str) {
+pub fn check_meta_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) {
if let ast::MacDelimiter::Parenthesis = delim {
return;
}
+ sess.emit_err(errors::MetaBadDelim {
+ span: span.entire(),
+ sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
+ });
+}
- sess.span_diagnostic
- .struct_span_err(span.entire(), msg)
- .multipart_suggestion(
- "the delimiters should be `(` and `)`",
- vec![(span.open, "(".to_string()), (span.close, ")".to_string())],
- Applicability::MachineApplicable,
- )
- .emit();
+pub fn check_cfg_attr_bad_delim(sess: &ParseSess, span: DelimSpan, delim: MacDelimiter) {
+ if let ast::MacDelimiter::Parenthesis = delim {
+ return;
+ }
+ sess.emit_err(errors::CfgAttrBadDelim {
+ span: span.entire(),
+ sugg: errors::MetaBadDelimSugg { open: span.open, close: span.close },
+ });
}
/// Checks that the given meta-item is compatible with this `AttributeTemplate`.
@@ -181,10 +186,10 @@ fn emit_malformed_attribute(
suggestions.push(code);
}
if should_warn(name) {
- sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, &msg);
+ sess.buffer_lint(&ILL_FORMED_ATTRIBUTE_INPUT, span, ast::CRATE_NODE_ID, msg);
} else {
sess.span_diagnostic
- .struct_span_err(span, &error_msg)
+ .struct_span_err(span, error_msg)
.span_suggestions(
span,
if suggestions.len() == 1 {
diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml
index 44f991f8c..0413b5b4f 100644
--- a/compiler/rustc_passes/Cargo.toml
+++ b/compiler/rustc_passes/Cargo.toml
@@ -12,6 +12,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_session = { path = "../rustc_session" }
rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_passes/messages.ftl b/compiler/rustc_passes/messages.ftl
index b354dca7c..7f9222dac 100644
--- a/compiler/rustc_passes/messages.ftl
+++ b/compiler/rustc_passes/messages.ftl
@@ -4,118 +4,185 @@
-passes_see_issue =
see issue #{$issue} <https://github.com/rust-lang/rust/issues/{$issue}> for more information
-passes_incorrect_do_not_recommend_location =
- `#[do_not_recommend]` can only be placed on trait implementations
+passes_abi =
+ abi: {$abi}
-passes_outer_crate_level_attr =
- crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
+passes_align =
+ align: {$align}
-passes_inner_crate_level_attr =
- crate-level attribute should be in the root module
+passes_allow_incoherent_impl =
+ `rustc_allow_incoherent_impl` attribute should be applied to impl items.
+ .label = the only currently supported targets are inherent methods
-passes_ignored_attr_with_macro =
- `#[{$sym}]` is ignored on struct fields, match arms and macro defs
- .warn = {-passes_previously_accepted}
- .note = {-passes_see_issue(issue: "80564")}
+passes_allow_internal_unstable =
+ attribute should be applied to a macro
+ .label = not a macro
-passes_ignored_attr =
- `#[{$sym}]` is ignored on struct fields and match arms
- .warn = {-passes_previously_accepted}
- .note = {-passes_see_issue(issue: "80564")}
+passes_attr_application_enum =
+ attribute should be applied to an enum
+ .label = not an enum
-passes_inline_ignored_function_prototype =
- `#[inline]` is ignored on function prototypes
+passes_attr_application_struct =
+ attribute should be applied to a struct
+ .label = not a struct
-passes_inline_ignored_constants =
- `#[inline]` is ignored on constants
- .warn = {-passes_previously_accepted}
- .note = {-passes_see_issue(issue: "65833")}
+passes_attr_application_struct_enum_function_method_union =
+ attribute should be applied to a struct, enum, function, associated function, or union
+ .label = not a struct, enum, function, associated function, or union
-passes_inline_not_fn_or_closure =
- attribute should be applied to function or closure
- .label = not a function or closure
+passes_attr_application_struct_enum_union =
+ attribute should be applied to a struct, enum, or union
+ .label = not a struct, enum, or union
-passes_no_coverage_ignored_function_prototype =
- `#[no_coverage]` is ignored on function prototypes
+passes_attr_application_struct_union =
+ attribute should be applied to a struct or union
+ .label = not a struct or union
-passes_no_coverage_propagate =
- `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
+passes_attr_crate_level =
+ this attribute can only be applied at the crate level
+ .suggestion = to apply to the crate, use an inner attribute
+ .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
-passes_no_coverage_fn_defn =
- `#[no_coverage]` may only be applied to function definitions
+passes_attr_only_in_functions =
+ `{$attr}` attribute can only be used on functions
-passes_no_coverage_not_coverable =
- `#[no_coverage]` must be applied to coverable code
- .label = not coverable code
+passes_attr_only_on_main =
+ `{$attr}` attribute can only be used on `fn main()`
-passes_should_be_applied_to_fn =
- attribute should be applied to a function definition
- .label = {$on_crate ->
- [true] cannot be applied to crates
- *[false] not a function definition
- }
+passes_attr_only_on_root_main =
+ `{$attr}` attribute can only be used on root `fn main()`
-passes_naked_tracked_caller =
- cannot use `#[track_caller]` with `#[naked]`
+passes_both_ffi_const_and_pure =
+ `#[ffi_const]` function cannot be `#[ffi_pure]`
-passes_should_be_applied_to_struct_enum =
- attribute should be applied to a struct or enum
- .label = not a struct or enum
+passes_break_inside_async_block =
+ `{$name}` inside of an `async` block
+ .label = cannot `{$name}` inside of an `async` block
+ .async_block_label = enclosing `async` block
-passes_should_be_applied_to_trait =
- attribute should be applied to a trait
- .label = not a trait
+passes_break_inside_closure =
+ `{$name}` inside of a closure
+ .label = cannot `{$name}` inside of a closure
+ .closure_label = enclosing closure
-passes_target_feature_on_statement =
+passes_break_non_loop =
+ `break` with value from a `{$kind}` loop
+ .label = can only break with a value inside `loop` or breakable block
+ .label2 = you can't `break` with a value in a `{$kind}` loop
+ .suggestion = use `break` on its own without a value inside this `{$kind}` loop
+ .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+
+passes_cannot_inline_naked_function =
+ naked functions cannot be inlined
+
+passes_cannot_stabilize_deprecated =
+ an API can't be stabilized after it is deprecated
+ .label = invalid version
+ .item = the stability attribute annotates this item
+
+passes_change_fields_to_be_of_unit_type =
+ consider changing the { $num ->
+ [one] field
+ *[other] fields
+ } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num ->
+ [one] field
+ *[other] fields
+ }
+
+passes_cold =
{passes_should_be_applied_to_fn}
.warn = {-passes_previously_accepted}
.label = {passes_should_be_applied_to_fn.label}
-passes_should_be_applied_to_static =
- attribute should be applied to a static
- .label = not a static
+passes_collapse_debuginfo =
+ `collapse_debuginfo` attribute should be applied to macro definitions
+ .label = not a macro definition
-passes_doc_expect_str =
- doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
+passes_const_impl_const_trait =
+ const `impl`s must be for traits marked with `#[const_trait]`
+ .note = this trait must be annotated with `#[const_trait]`
-passes_doc_alias_empty =
- {$attr_str} attribute cannot have empty value
+passes_const_trait =
+ attribute should be applied to a trait
+
+passes_continue_labeled_block =
+ `continue` pointing to a labeled block
+ .label = labeled blocks cannot be `continue`'d
+ .block_label = labeled block the `continue` points to
+
+passes_dead_codes =
+ { $multiple ->
+ *[true] multiple {$descr}s are
+ [false] { $num ->
+ [one] {$descr} {$name_list} is
+ *[other] {$descr}s {$name_list} are
+ }
+ } never {$participle}
+
+passes_debug_visualizer_invalid =
+ invalid argument
+ .note_1 = expected: `natvis_file = "..."`
+ .note_2 = OR
+ .note_3 = expected: `gdb_script_file = "..."`
+
+passes_debug_visualizer_placement =
+ attribute should be applied to a module
+
+passes_debug_visualizer_unreadable =
+ couldn't read {$file}: {$error}
+
+passes_deprecated =
+ attribute is ignored here
+
+passes_deprecated_annotation_has_no_effect =
+ this `#[deprecated]` annotation has no effect
+ .suggestion = remove the unnecessary deprecation attribute
+
+passes_deprecated_attribute =
+ deprecated attribute must be paired with either stable or unstable attribute
+
+passes_diagnostic_item_first_defined =
+ the diagnostic item is first defined here
passes_doc_alias_bad_char =
{$char_} character isn't allowed in {$attr_str}
-passes_doc_alias_start_end =
- {$attr_str} cannot start or end with ' '
-
passes_doc_alias_bad_location =
{$attr_str} isn't allowed on {$location}
-passes_doc_alias_not_an_alias =
- {$attr_str} is the same as the item's name
-
passes_doc_alias_duplicated = doc alias is duplicated
.label = first defined here
-passes_doc_alias_not_string_literal =
- `#[doc(alias("a"))]` expects string literals
+passes_doc_alias_empty =
+ {$attr_str} attribute cannot have empty value
passes_doc_alias_malformed =
doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]`
-passes_doc_keyword_empty_mod =
- `#[doc(keyword = "...")]` should be used on empty modules
+passes_doc_alias_not_an_alias =
+ {$attr_str} is the same as the item's name
-passes_doc_keyword_not_mod =
- `#[doc(keyword = "...")]` should be used on modules
+passes_doc_alias_not_string_literal =
+ `#[doc(alias("a"))]` expects string literals
-passes_doc_keyword_invalid_ident =
- `{$doc_keyword}` is not a valid identifier
+passes_doc_alias_start_end =
+ {$attr_str} cannot start or end with ' '
+
+passes_doc_attr_not_crate_level =
+ `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
+
+passes_doc_cfg_hide_takes_list =
+ `#[doc(cfg_hide(...)]` takes a list of attributes
+
+passes_doc_expect_str =
+ doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")]
passes_doc_fake_variadic_not_valid =
`#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity
-passes_doc_keyword_only_impl =
- `#[doc(keyword = "...")]` should be used on impl blocks
+passes_doc_inline_conflict =
+ conflicting doc inlining attributes
+ .help = remove one of the conflicting attributes
passes_doc_inline_conflict_first =
this attribute...
@@ -123,384 +190,274 @@ passes_doc_inline_conflict_first =
passes_doc_inline_conflict_second =
{"."}..conflicts with this attribute
-passes_doc_inline_conflict =
- conflicting doc inlining attributes
- .help = remove one of the conflicting attributes
-
passes_doc_inline_only_use =
this attribute can only be applied to a `use` item
.label = only applicable on `use` items
.not_a_use_item_label = not a `use` item
.note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#inline-and-no_inline> for more information
-passes_doc_attr_not_crate_level =
- `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute
+passes_doc_invalid =
+ invalid `doc` attribute
-passes_attr_crate_level =
- this attribute can only be applied at the crate level
- .suggestion = to apply to the crate, use an inner attribute
- .help = to apply to the crate, use an inner attribute
- .note = read <https://doc.rust-lang.org/nightly/rustdoc/the-doc-attribute.html#at-the-crate-level> for more information
+passes_doc_keyword_empty_mod =
+ `#[doc(keyword = "...")]` should be used on empty modules
-passes_doc_test_unknown =
- unknown `doc(test)` attribute `{$path}`
+passes_doc_keyword_invalid_ident =
+ `{$doc_keyword}` is not a valid identifier
+
+passes_doc_keyword_not_mod =
+ `#[doc(keyword = "...")]` should be used on modules
+
+passes_doc_keyword_only_impl =
+ `#[doc(keyword = "...")]` should be used on impl blocks
passes_doc_test_takes_list =
`#[doc(test(...)]` takes a list of attributes
-passes_doc_cfg_hide_takes_list =
- `#[doc(cfg_hide(...)]` takes a list of attributes
+passes_doc_test_unknown =
+ unknown `doc(test)` attribute `{$path}`
passes_doc_test_unknown_any =
unknown `doc` attribute `{$path}`
+passes_doc_test_unknown_include =
+ unknown `doc` attribute `{$path}`
+ .suggestion = use `doc = include_str!` instead
+
passes_doc_test_unknown_spotlight =
unknown `doc` attribute `{$path}`
.note = `doc(spotlight)` was renamed to `doc(notable_trait)`
.suggestion = use `notable_trait` instead
.no_op_note = `doc(spotlight)` is now a no-op
-passes_doc_test_unknown_include =
- unknown `doc` attribute `{$path}`
- .suggestion = use `doc = include_str!` instead
+passes_duplicate_diagnostic_item_in_crate =
+ duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
+ .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
-passes_doc_invalid =
- invalid `doc` attribute
+passes_duplicate_feature_err =
+ the feature `{$feature}` has already been declared
-passes_pass_by_value =
- `pass_by_value` attribute should be applied to a struct, enum or type alias
- .label = is not a struct, enum or type alias
+passes_duplicate_lang_item =
+ found duplicate lang item `{$lang_item_name}`
+ .first_defined_span = the lang item is first defined here
+ .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+ .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+ .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+ .second_definition_local = second definition in the local crate (`{$crate_name}`)
+ .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+ .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
-passes_allow_incoherent_impl =
- `rustc_allow_incoherent_impl` attribute should be applied to impl items.
- .label = the only currently supported targets are inherent methods
+passes_duplicate_lang_item_crate =
+ duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`.
+ .first_defined_span = the lang item is first defined here
+ .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+ .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+ .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+ .second_definition_local = second definition in the local crate (`{$crate_name}`)
+ .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+ .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
-passes_has_incoherent_inherent_impl =
- `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
- .label = only adts, extern types and traits are supported
+passes_duplicate_lang_item_crate_depends =
+ duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`.
+ .first_defined_span = the lang item is first defined here
+ .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
+ .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
+ .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
+ .second_definition_local = second definition in the local crate (`{$crate_name}`)
+ .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
+ .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
-passes_both_ffi_const_and_pure =
- `#[ffi_const]` function cannot be `#[ffi_pure]`
+passes_export_name =
+ attribute should be applied to a free function, impl method or static
+ .label = not a free function, impl method or static
-passes_ffi_pure_invalid_target =
- `#[ffi_pure]` may only be used on foreign functions
+passes_expr_not_allowed_in_context =
+ {$expr} is not allowed in a `{$context}`
+
+passes_extern_main =
+ the `main` function cannot be declared in an `extern` block
+
+passes_feature_only_on_nightly =
+ `#![feature]` may not be used on the {$release_channel} release channel
+
+passes_feature_previously_declared =
+ feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+
+passes_feature_stable_twice =
+ feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
passes_ffi_const_invalid_target =
`#[ffi_const]` may only be used on foreign functions
+passes_ffi_pure_invalid_target =
+ `#[ffi_pure]` may only be used on foreign functions
+
passes_ffi_returns_twice_invalid_target =
`#[ffi_returns_twice]` may only be used on foreign functions
-passes_must_use_async =
- `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
- .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
-
-passes_must_use_no_effect =
- `#[must_use]` has no effect when applied to {$article} {$target}
-
-passes_must_not_suspend =
- `must_not_suspend` attribute should be applied to a struct, enum, or trait
- .label = is not a struct, enum, or trait
+passes_has_incoherent_inherent_impl =
+ `rustc_has_incoherent_inherent_impls` attribute should be applied to types or traits.
+ .label = only adts, extern types and traits are supported
-passes_cold =
- {passes_should_be_applied_to_fn}
- .warn = {-passes_previously_accepted}
- .label = {passes_should_be_applied_to_fn.label}
+passes_homogeneous_aggregate =
+ homogeneous_aggregate: {$homogeneous_aggregate}
-passes_link =
- attribute should be applied to an `extern` block with non-Rust ABI
+passes_ignored_attr =
+ `#[{$sym}]` is ignored on struct fields and match arms
.warn = {-passes_previously_accepted}
- .label = not an `extern` block
+ .note = {-passes_see_issue(issue: "80564")}
-passes_link_name =
- attribute should be applied to a foreign function or static
+passes_ignored_attr_with_macro =
+ `#[{$sym}]` is ignored on struct fields, match arms and macro defs
.warn = {-passes_previously_accepted}
- .label = not a foreign function or static
- .help = try `#[link(name = "{$value}")]` instead
-
-passes_no_link =
- attribute should be applied to an `extern crate` item
- .label = not an `extern crate` item
-
-passes_export_name =
- attribute should be applied to a free function, impl method or static
- .label = not a free function, impl method or static
-
-passes_rustc_layout_scalar_valid_range_not_struct =
- attribute should be applied to a struct
- .label = not a struct
+ .note = {-passes_see_issue(issue: "80564")}
-passes_rustc_layout_scalar_valid_range_arg =
- expected exactly one integer literal argument
+passes_ignored_derived_impls =
+ `{$name}` has {$trait_list_len ->
+ [one] a derived impl
+ *[other] derived impls
+ } for the {$trait_list_len ->
+ [one] trait {$trait_list}, but this is
+ *[other] traits {$trait_list}, but these are
+ } intentionally ignored during dead code analysis
-passes_rustc_legacy_const_generics_only =
- #[rustc_legacy_const_generics] functions must only have const generics
- .label = non-const generic parameter
+passes_implied_feature_not_exist =
+ feature `{$implied_by}` implying `{$feature}` does not exist
-passes_rustc_legacy_const_generics_index =
- #[rustc_legacy_const_generics] must have one index for each generic parameter
- .label = generic parameters
+passes_incorrect_do_not_recommend_location =
+ `#[do_not_recommend]` can only be placed on trait implementations
-passes_rustc_legacy_const_generics_index_exceed =
- index exceeds number of arguments
- .label = there {$arg_count ->
- [one] is
- *[other] are
- } only {$arg_count} {$arg_count ->
+passes_incorrect_target =
+ `{$name}` language item must be applied to a {$kind} with {$at_least ->
+ [true] at least {$num}
+ *[false] {$num}
+ } generic {$num ->
+ [one] argument
+ *[other] arguments
+ }
+ .label = this {$kind} has {$actual_num} generic {$actual_num ->
[one] argument
*[other] arguments
}
-passes_rustc_legacy_const_generics_index_negative =
- arguments should be non-negative integers
-
-passes_rustc_dirty_clean =
- attribute requires -Z query-dep-graph to be enabled
-
-passes_link_section =
- attribute should be applied to a function or static
- .warn = {-passes_previously_accepted}
- .label = not a function or static
-
-passes_no_mangle_foreign =
- `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
- .warn = {-passes_previously_accepted}
- .label = foreign {$foreign_item_kind}
- .note = symbol names in extern blocks are not mangled
- .suggestion = remove this attribute
+passes_ineffective_unstable_impl = an `#[unstable]` annotation here has no effect
+ .note = see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information
-passes_no_mangle =
- attribute should be applied to a free function, impl method or static
+passes_inline_ignored_constants =
+ `#[inline]` is ignored on constants
.warn = {-passes_previously_accepted}
- .label = not a free function, impl method or static
-
-passes_repr_ident =
- meta item in `repr` must be an identifier
-
-passes_repr_conflicting =
- conflicting representation hints
-
-passes_used_static =
- attribute must be applied to a `static` variable
-
-passes_used_compiler_linker =
- `used(compiler)` and `used(linker)` can't be used together
-
-passes_allow_internal_unstable =
- attribute should be applied to a macro
- .label = not a macro
-
-passes_debug_visualizer_placement =
- attribute should be applied to a module
-
-passes_debug_visualizer_invalid =
- invalid argument
- .note_1 = expected: `natvis_file = "..."`
- .note_2 = OR
- .note_3 = expected: `gdb_script_file = "..."`
-
-passes_debug_visualizer_unreadable =
- couldn't read {$file}: {$error}
-
-passes_rustc_allow_const_fn_unstable =
- attribute should be applied to `const fn`
- .label = not a `const fn`
-
-passes_rustc_std_internal_symbol =
- attribute should be applied to functions or statics
- .label = not a function or static
-
-passes_const_trait =
- attribute should be applied to a trait
-
-passes_stability_promotable =
- attribute cannot be applied to an expression
-
-passes_deprecated =
- attribute is ignored here
-
-passes_macro_use =
- `#[{$name}]` only has an effect on `extern crate` and modules
-
-passes_macro_export =
- `#[macro_export]` only has an effect on macro definitions
-
-passes_plugin_registrar =
- `#[plugin_registrar]` only has an effect on functions
-
-passes_unused_empty_lints_note =
- attribute `{$name}` with an empty list has no effect
-
-passes_unused_no_lints_note =
- attribute `{$name}` without any lints has no effect
-
-passes_unused_default_method_body_const_note =
- `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+ .note = {-passes_see_issue(issue: "65833")}
-passes_unused =
- unused attribute
- .suggestion = remove this attribute
+passes_inline_ignored_function_prototype =
+ `#[inline]` is ignored on function prototypes
-passes_non_exported_macro_invalid_attrs =
+passes_inline_not_fn_or_closure =
attribute should be applied to function or closure
.label = not a function or closure
-passes_unused_duplicate =
- unused attribute
- .suggestion = remove this attribute
- .note = attribute also specified here
- .warn = {-passes_previously_accepted}
-
-passes_unused_multiple =
- multiple `{$name}` attributes
- .suggestion = remove this attribute
- .note = attribute also specified here
-
-passes_rustc_lint_opt_ty =
- `#[rustc_lint_opt_ty]` should be applied to a struct
- .label = not a struct
-
-passes_rustc_lint_opt_deny_field_access =
- `#[rustc_lint_opt_deny_field_access]` should be applied to a field
- .label = not a field
-
-passes_link_ordinal =
- attribute should be applied to a foreign function or static
- .label = not a foreign function or static
-
-passes_collapse_debuginfo =
- `collapse_debuginfo` attribute should be applied to macro definitions
- .label = not a macro definition
-
-passes_deprecated_annotation_has_no_effect =
- this `#[deprecated]` annotation has no effect
- .suggestion = remove the unnecessary deprecation attribute
-
-passes_unknown_external_lang_item =
- unknown external lang item: `{$lang_item}`
-
-passes_missing_panic_handler =
- `#[panic_handler]` function required, but not found
-
-passes_missing_lang_item =
- language item required, but not found: `{$name}`
- .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
- .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
-
-passes_lang_item_on_incorrect_target =
- `{$name}` language item must be applied to a {$expected_target}
- .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
-
-passes_unknown_lang_item =
- definition of an unknown language item: `{$name}`
- .label = definition of unknown language item `{$name}`
+passes_inner_crate_level_attr =
+ crate-level attribute should be in the root module
passes_invalid_attr_at_crate_level =
`{$name}` attribute cannot be used at crate level
.suggestion = perhaps you meant to use an outer attribute
-passes_duplicate_diagnostic_item_in_crate =
- duplicate diagnostic item in crate `{$crate_name}`: `{$name}`.
- .note = the diagnostic item is first defined in crate `{$orig_crate_name}`.
+passes_invalid_deprecation_version =
+ invalid deprecation version found
+ .label = invalid deprecation version
+ .item = the stability attribute annotates this item
-passes_diagnostic_item_first_defined =
- the diagnostic item is first defined here
+passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
-passes_abi =
- abi: {$abi}
+passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
-passes_align =
- align: {$align}
+passes_invalid_stability =
+ invalid stability version found
+ .label = invalid stability version
+ .item = the stability attribute annotates this item
-passes_size =
- size: {$size}
+passes_lang_item_on_incorrect_target =
+ `{$name}` language item must be applied to a {$expected_target}
+ .label = attribute should be applied to a {$expected_target}, not a {$actual_target}
-passes_homogeneous_aggregate =
- homogeneous_aggregate: {$homogeneous_aggregate}
+passes_layout =
+ layout error: {$layout_error}
passes_layout_of =
layout_of({$normalized_ty}) = {$ty_layout}
-passes_unrecognized_field =
- unrecognized field name `{$name}`
-
-passes_layout =
- layout error: {$layout_error}
+passes_link =
+ attribute should be applied to an `extern` block with non-Rust ABI
+ .warn = {-passes_previously_accepted}
+ .label = not an `extern` block
-passes_feature_stable_twice =
- feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since}
+passes_link_name =
+ attribute should be applied to a foreign function or static
+ .warn = {-passes_previously_accepted}
+ .label = not a foreign function or static
+ .help = try `#[link(name = "{$value}")]` instead
-passes_feature_previously_declared =
- feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared}
+passes_link_ordinal =
+ attribute should be applied to a foreign function or static
+ .label = not a foreign function or static
-passes_expr_not_allowed_in_context =
- {$expr} is not allowed in a `{$context}`
+passes_link_section =
+ attribute should be applied to a function or static
+ .warn = {-passes_previously_accepted}
+ .label = not a function or static
-passes_const_impl_const_trait =
- const `impl`s must be for traits marked with `#[const_trait]`
- .note = this trait must be annotated with `#[const_trait]`
+passes_macro_export =
+ `#[macro_export]` only has an effect on macro definitions
-passes_break_non_loop =
- `break` with value from a `{$kind}` loop
- .label = can only break with a value inside `loop` or breakable block
- .label2 = you can't `break` with a value in a `{$kind}` loop
- .suggestion = use `break` on its own without a value inside this `{$kind}` loop
- .break_expr_suggestion = alternatively, you might have meant to use the available loop label
+passes_macro_use =
+ `#[{$name}]` only has an effect on `extern crate` and modules
-passes_continue_labeled_block =
- `continue` pointing to a labeled block
- .label = labeled blocks cannot be `continue`'d
- .block_label = labeled block the `continue` points to
+passes_maybe_string_interpolation = you might have meant to use string interpolation in this string literal
+passes_missing_const_err =
+ attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
+ .help = make the function or method const
+ .label = attribute specified here
-passes_break_inside_closure =
- `{$name}` inside of a closure
- .label = cannot `{$name}` inside of a closure
- .closure_label = enclosing closure
+passes_missing_const_stab_attr =
+ {$descr} has missing const stability attribute
-passes_break_inside_async_block =
- `{$name}` inside of an `async` block
- .label = cannot `{$name}` inside of an `async` block
- .async_block_label = enclosing `async` block
+passes_missing_lang_item =
+ language item required, but not found: `{$name}`
+ .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library
+ .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config`
-passes_outside_loop =
- `{$name}` outside of a loop{$is_break ->
- [true] {" or labeled block"}
- *[false] {""}
- }
- .label = cannot `{$name}` outside of a loop{$is_break ->
- [true] {" or labeled block"}
- *[false] {""}
- }
+passes_missing_panic_handler =
+ `#[panic_handler]` function required, but not found
-passes_unlabeled_in_labeled_block =
- unlabeled `{$cf_type}` inside of a labeled block
- .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
+passes_missing_stability_attr =
+ {$descr} has missing stability attribute
-passes_unlabeled_cf_in_while_condition =
- `break` or `continue` with no label in the condition of a `while` loop
- .label = unlabeled `{$cf_type}` in the condition of a `while` loop
+passes_multiple_rustc_main =
+ multiple functions with a `#[rustc_main]` attribute
+ .first = first `#[rustc_main]` function
+ .additional = additional `#[rustc_main]` function
-passes_cannot_inline_naked_function =
- naked functions cannot be inlined
+passes_multiple_start_functions =
+ multiple `start` functions
+ .label = multiple `start` functions
+ .previous = previous `#[start]` function here
-passes_undefined_naked_function_abi =
- Rust ABI is unsupported in naked functions
+passes_must_not_suspend =
+ `must_not_suspend` attribute should be applied to a struct, enum, or trait
+ .label = is not a struct, enum, or trait
-passes_no_patterns =
- patterns not allowed in naked function parameters
+passes_must_use_async =
+ `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within
+ .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use`
-passes_params_not_allowed =
- referencing function parameters is not allowed in naked functions
- .help = follow the calling convention in asm block to use parameters
+passes_must_use_no_effect =
+ `#[must_use]` has no effect when applied to {$article} {$target}
passes_naked_functions_asm_block =
naked functions must contain a single asm block
.label_multiple_asm = multiple asm blocks are unsupported in naked functions
.label_non_asm = non-asm is unsupported in naked functions
-passes_naked_functions_operands =
- only `const` and `sym` operands are supported in naked functions
-
passes_naked_functions_asm_options =
asm options unsupported in naked functions: {$unsupported_options}
@@ -508,30 +465,28 @@ passes_naked_functions_must_use_noreturn =
asm in naked functions must use `noreturn` option
.suggestion = consider specifying that the asm block is responsible for returning from the function
-passes_attr_only_on_main =
- `{$attr}` attribute can only be used on `fn main()`
+passes_naked_functions_operands =
+ only `const` and `sym` operands are supported in naked functions
-passes_attr_only_on_root_main =
- `{$attr}` attribute can only be used on root `fn main()`
+passes_naked_tracked_caller =
+ cannot use `#[track_caller]` with `#[naked]`
-passes_attr_only_in_functions =
- `{$attr}` attribute can only be used on functions
+passes_no_coverage_fn_defn =
+ `#[no_coverage]` may only be applied to function definitions
-passes_multiple_rustc_main =
- multiple functions with a `#[rustc_main]` attribute
- .first = first `#[rustc_main]` function
- .additional = additional `#[rustc_main]` function
+passes_no_coverage_ignored_function_prototype =
+ `#[no_coverage]` is ignored on function prototypes
-passes_multiple_start_functions =
- multiple `start` functions
- .label = multiple `start` functions
- .previous = previous `#[start]` function here
+passes_no_coverage_not_coverable =
+ `#[no_coverage]` must be applied to coverable code
+ .label = not coverable code
-passes_extern_main =
- the `main` function cannot be declared in an `extern` block
+passes_no_coverage_propagate =
+ `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly
-passes_unix_sigpipe_values =
- valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+passes_no_link =
+ attribute should be applied to an `extern crate` item
+ .label = not an `extern crate` item
passes_no_main_function =
`main` function not found in crate `{$crate_name}`
@@ -547,54 +502,27 @@ passes_no_main_function =
.teach_note = If you don't know the basics of Rust, you can go look to the Rust Book to get started: https://doc.rust-lang.org/book/
.non_function_main = non-function item at `crate::main` is found
-passes_duplicate_lang_item =
- found duplicate lang item `{$lang_item_name}`
- .first_defined_span = the lang item is first defined here
- .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
- .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
- .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
- .second_definition_local = second definition in the local crate (`{$crate_name}`)
- .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
- .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+passes_no_mangle =
+ attribute should be applied to a free function, impl method or static
+ .warn = {-passes_previously_accepted}
+ .label = not a free function, impl method or static
-passes_duplicate_lang_item_crate =
- duplicate lang item in crate `{$crate_name}`: `{$lang_item_name}`.
- .first_defined_span = the lang item is first defined here
- .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
- .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
- .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
- .second_definition_local = second definition in the local crate (`{$crate_name}`)
- .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
- .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+passes_no_mangle_foreign =
+ `#[no_mangle]` has no effect on a foreign {$foreign_item_kind}
+ .warn = {-passes_previously_accepted}
+ .label = foreign {$foreign_item_kind}
+ .note = symbol names in extern blocks are not mangled
+ .suggestion = remove this attribute
-passes_duplicate_lang_item_crate_depends =
- duplicate lang item in crate `{$crate_name}` (which `{$dependency_of}` depends on): `{$lang_item_name}`.
- .first_defined_span = the lang item is first defined here
- .first_defined_crate_depends = the lang item is first defined in crate `{$orig_crate_name}` (which `{$orig_dependency_of}` depends on)
- .first_defined_crate = the lang item is first defined in crate `{$orig_crate_name}`.
- .first_definition_local = first definition in the local crate (`{$orig_crate_name}`)
- .second_definition_local = second definition in the local crate (`{$crate_name}`)
- .first_definition_path = first definition in `{$orig_crate_name}` loaded from {$orig_path}
- .second_definition_path = second definition in `{$crate_name}` loaded from {$path}
+passes_no_patterns =
+ patterns not allowed in naked function parameters
-passes_incorrect_target =
- `{$name}` language item must be applied to a {$kind} with {$at_least ->
- [true] at least {$num}
- *[false] {$num}
- } generic {$num ->
- [one] argument
- *[other] arguments
- }
- .label = this {$kind} has {$actual_num} generic {$actual_num ->
- [one] argument
- *[other] arguments
- }
+passes_non_exported_macro_invalid_attrs =
+ attribute should be applied to function or closure
+ .label = not a function or closure
-passes_useless_assignment =
- useless assignment of {$is_field_assign ->
- [true] field
- *[false] variable
- } of type `{$ty}` to itself
+passes_object_lifetime_err =
+ {$repr}
passes_only_has_effect_on =
`#[{$attr_name}]` only has an effect on {$target_name ->
@@ -604,123 +532,236 @@ passes_only_has_effect_on =
*[unspecified] (unspecified--this is a compiler bug)
}
-passes_object_lifetime_err =
- {$repr}
+passes_outer_crate_level_attr =
+ crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]`
-passes_unrecognized_repr_hint =
- unrecognized representation hint
- .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
+passes_outside_loop =
+ `{$name}` outside of a loop{$is_break ->
+ [true] {" or labeled block"}
+ *[false] {""}
+ }
+ .label = cannot `{$name}` outside of a loop{$is_break ->
+ [true] {" or labeled block"}
+ *[false] {""}
+ }
-passes_attr_application_enum =
- attribute should be applied to an enum
- .label = not an enum
+passes_params_not_allowed =
+ referencing function parameters is not allowed in naked functions
+ .help = follow the calling convention in asm block to use parameters
-passes_attr_application_struct =
+passes_parent_info =
+ {$num ->
+ [one] {$descr}
+ *[other] {$descr}s
+ } in this {$parent_descr}
+
+passes_pass_by_value =
+ `pass_by_value` attribute should be applied to a struct, enum or type alias
+ .label = is not a struct, enum or type alias
+
+passes_plugin_registrar =
+ `#[plugin_registrar]` only has an effect on functions
+
+passes_proc_macro_bad_sig = {$kind} has incorrect signature
+
+passes_repr_conflicting =
+ conflicting representation hints
+
+passes_repr_ident =
+ meta item in `repr` must be an identifier
+
+passes_rustc_allow_const_fn_unstable =
+ attribute should be applied to `const fn`
+ .label = not a `const fn`
+
+passes_rustc_dirty_clean =
+ attribute requires -Z query-dep-graph to be enabled
+
+passes_rustc_layout_scalar_valid_range_arg =
+ expected exactly one integer literal argument
+
+passes_rustc_layout_scalar_valid_range_not_struct =
attribute should be applied to a struct
.label = not a struct
-passes_attr_application_struct_union =
- attribute should be applied to a struct or union
- .label = not a struct or union
+passes_rustc_legacy_const_generics_index =
+ #[rustc_legacy_const_generics] must have one index for each generic parameter
+ .label = generic parameters
-passes_attr_application_struct_enum_union =
- attribute should be applied to a struct, enum, or union
- .label = not a struct, enum, or union
+passes_rustc_legacy_const_generics_index_exceed =
+ index exceeds number of arguments
+ .label = there {$arg_count ->
+ [one] is
+ *[other] are
+ } only {$arg_count} {$arg_count ->
+ [one] argument
+ *[other] arguments
+ }
-passes_attr_application_struct_enum_function_union =
- attribute should be applied to a struct, enum, function, or union
- .label = not a struct, enum, function, or union
+passes_rustc_legacy_const_generics_index_negative =
+ arguments should be non-negative integers
-passes_transparent_incompatible =
- transparent {$target} cannot have other repr hints
+passes_rustc_legacy_const_generics_only =
+ #[rustc_legacy_const_generics] functions must only have const generics
+ .label = non-const generic parameter
-passes_deprecated_attribute =
- deprecated attribute must be paired with either stable or unstable attribute
+passes_rustc_lint_opt_deny_field_access =
+ `#[rustc_lint_opt_deny_field_access]` should be applied to a field
+ .label = not a field
-passes_useless_stability =
- this stability annotation is useless
- .label = useless stability annotation
- .item = the stability attribute annotates this item
+passes_rustc_lint_opt_ty =
+ `#[rustc_lint_opt_ty]` should be applied to a struct
+ .label = not a struct
-passes_invalid_stability =
- invalid stability version found
- .label = invalid stability version
- .item = the stability attribute annotates this item
+passes_rustc_std_internal_symbol =
+ attribute should be applied to functions or statics
+ .label = not a function or static
-passes_cannot_stabilize_deprecated =
- an API can't be stabilized after it is deprecated
- .label = invalid version
- .item = the stability attribute annotates this item
+passes_should_be_applied_to_fn =
+ attribute should be applied to a function definition
+ .label = {$on_crate ->
+ [true] cannot be applied to crates
+ *[false] not a function definition
+ }
-passes_invalid_deprecation_version =
- invalid deprecation version found
- .label = invalid deprecation version
- .item = the stability attribute annotates this item
+passes_should_be_applied_to_static =
+ attribute should be applied to a static
+ .label = not a static
-passes_missing_stability_attr =
- {$descr} has missing stability attribute
+passes_should_be_applied_to_struct_enum =
+ attribute should be applied to a struct or enum
+ .label = not a struct or enum
-passes_missing_const_stab_attr =
- {$descr} has missing const stability attribute
+passes_should_be_applied_to_trait =
+ attribute should be applied to a trait
+ .label = not a trait
+
+passes_size =
+ size: {$size}
+
+passes_skipping_const_checks = skipping const checks
+
+passes_stability_promotable =
+ attribute cannot be applied to an expression
+
+passes_string_interpolation_only_works = string interpolation only works in `format!` invocations
+
+passes_target_feature_on_statement =
+ {passes_should_be_applied_to_fn}
+ .warn = {-passes_previously_accepted}
+ .label = {passes_should_be_applied_to_fn.label}
passes_trait_impl_const_stable =
trait implementations cannot be const stable yet
.note = see issue #67792 <https://github.com/rust-lang/rust/issues/67792> for more information
-passes_feature_only_on_nightly =
- `#![feature]` may not be used on the {$release_channel} release channel
+passes_transparent_incompatible =
+ transparent {$target} cannot have other repr hints
+
+passes_undefined_naked_function_abi =
+ Rust ABI is unsupported in naked functions
+
+passes_unix_sigpipe_values =
+ valid values for `#[unix_sigpipe = "..."]` are `inherit`, `sig_ign`, or `sig_dfl`
+
+passes_unknown_external_lang_item =
+ unknown external lang item: `{$lang_item}`
passes_unknown_feature =
unknown feature `{$feature}`
-passes_implied_feature_not_exist =
- feature `{$implied_by}` implying `{$feature}` does not exist
+passes_unknown_lang_item =
+ definition of an unknown language item: `{$name}`
+ .label = definition of unknown language item `{$name}`
-passes_duplicate_feature_err =
- the feature `{$feature}` has already been declared
+passes_unlabeled_cf_in_while_condition =
+ `break` or `continue` with no label in the condition of a `while` loop
+ .label = unlabeled `{$cf_type}` in the condition of a `while` loop
-passes_missing_const_err =
- attributes `#[rustc_const_unstable]` and `#[rustc_const_stable]` require the function or method to be `const`
- .help = make the function or method const
- .label = attribute specified here
+passes_unlabeled_in_labeled_block =
+ unlabeled `{$cf_type}` inside of a labeled block
+ .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label
-passes_dead_codes =
- { $multiple ->
- *[true] multiple {$descr}s are
- [false] { $num ->
- [one] {$descr} {$name_list} is
- *[other] {$descr}s {$name_list} are
- }
- } never {$participle}
+passes_unnecessary_partial_stable_feature = the feature `{$feature}` has been partially stabilized since {$since} and is succeeded by the feature `{$implies}`
+ .suggestion = if you are using features which are still unstable, change to using `{$implies}`
+ .suggestion_remove = if you are using features which are now stable, remove this line
-passes_change_fields_to_be_of_unit_type =
- consider changing the { $num ->
- [one] field
- *[other] fields
- } to be of unit type to suppress this warning while preserving the field numbering, or remove the { $num ->
- [one] field
- *[other] fields
- }
+passes_unnecessary_stable_feature = the feature `{$feature}` has been stable since {$since} and no longer requires an attribute to enable
-passes_parent_info =
- {$num ->
- [one] {$descr}
- *[other] {$descr}s
- } in this {$parent_descr}
+passes_unreachable_due_to_uninhabited = unreachable {$descr}
+ .label = unreachable {$descr}
+ .label_orig = any code following this expression is unreachable
+ .note = this expression has type `{$ty}`, which is uninhabited
-passes_ignored_derived_impls =
- `{$name}` has {$trait_list_len ->
- [one] a derived impl
- *[other] derived impls
- } for the {$trait_list_len ->
- [one] trait {$trait_list}, but this is
- *[other] traits {$trait_list}, but these are
- } intentionally ignored during dead code analysis
+passes_unrecognized_field =
+ unrecognized field name `{$name}`
-passes_proc_macro_bad_sig = {$kind} has incorrect signature
+passes_unrecognized_repr_hint =
+ unrecognized representation hint
+ .help = valid reprs are `C`, `align`, `packed`, `transparent`, `simd`, `i8`, `u8`, `i16`, `u16`, `i32`, `u32`, `i64`, `u64`, `i128`, `u128`, `isize`, `usize`
-passes_skipping_const_checks = skipping const checks
+passes_unused =
+ unused attribute
+ .suggestion = remove this attribute
-passes_invalid_macro_export_arguments = `{$name}` isn't a valid `#[macro_export]` argument
+passes_unused_assign = value assigned to `{$name}` is never read
+ .help = maybe it is overwritten before being read?
-passes_invalid_macro_export_arguments_too_many_items = `#[macro_export]` can only take 1 or 0 arguments
+passes_unused_assign_passed = value passed to `{$name}` is never read
+ .help = maybe it is overwritten before being read?
+
+passes_unused_capture_maybe_capture_ref = value captured by `{$name}` is never read
+ .help = did you mean to capture by reference instead?
+
+passes_unused_default_method_body_const_note =
+ `default_method_body_is_const` has been replaced with `#[const_trait]` on traits
+
+passes_unused_duplicate =
+ unused attribute
+ .suggestion = remove this attribute
+ .note = attribute also specified here
+ .warn = {-passes_previously_accepted}
+
+passes_unused_empty_lints_note =
+ attribute `{$name}` with an empty list has no effect
+
+passes_unused_multiple =
+ multiple `{$name}` attributes
+ .suggestion = remove this attribute
+ .note = attribute also specified here
+
+passes_unused_no_lints_note =
+ attribute `{$name}` without any lints has no effect
+
+passes_unused_var_assigned_only = variable `{$name}` is assigned to, but never used
+ .note = consider using `_{$name}` instead
+
+passes_unused_var_maybe_capture_ref = unused variable: `{$name}`
+ .help = did you mean to capture by reference instead?
+
+passes_unused_var_remove_field = unused variable: `{$name}`
+passes_unused_var_remove_field_suggestion = try removing the field
+
+passes_unused_variable_try_ignore = unused variable: `{$name}`
+ .suggestion = try ignoring the field
+
+passes_unused_variable_try_prefix = unused variable: `{$name}`
+ .label = unused variable
+ .suggestion = if this is intentional, prefix it with an underscore
+
+passes_used_compiler_linker =
+ `used(compiler)` and `used(linker)` can't be used together
+
+passes_used_static =
+ attribute must be applied to a `static` variable
+
+passes_useless_assignment =
+ useless assignment of {$is_field_assign ->
+ [true] field
+ *[false] variable
+ } of type `{$ty}` to itself
+
+passes_useless_stability =
+ this stability annotation is useless
+ .label = useless stability annotation
+ .item = the stability attribute annotates this item
diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs
index 80a93da2b..c3189d1fe 100644
--- a/compiler/rustc_passes/src/check_attr.rs
+++ b/compiler/rustc_passes/src/check_attr.rs
@@ -8,7 +8,6 @@ use crate::{errors, fluent_generated as fluent};
use rustc_ast::{ast, AttrStyle, Attribute, LitKind, MetaItemKind, MetaItemLit, NestedMetaItem};
use rustc_data_structures::fx::FxHashMap;
use rustc_errors::{Applicability, IntoDiagnosticArg, MultiSpan};
-use rustc_expand::base::resolve_path;
use rustc_feature::{AttributeDuplicates, AttributeType, BuiltinAttribute, BUILTIN_ATTRIBUTE_MAP};
use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
@@ -19,9 +18,9 @@ use rustc_hir::{
use rustc_hir::{MethodKind, Target, Unsafety};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::resolve_bound_vars::ObjectLifetimeDefault;
+use rustc_middle::query::Providers;
use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint::builtin::{
CONFLICTING_REPR_HINTS, INVALID_DOC_ATTRIBUTES, INVALID_MACRO_EXPORT_ARGUMENTS,
@@ -29,7 +28,7 @@ use rustc_session::lint::builtin::{
};
use rustc_session::parse::feature_err;
use rustc_span::symbol::{kw, sym, Symbol};
-use rustc_span::{Span, DUMMY_SP};
+use rustc_span::{BytePos, Span, DUMMY_SP};
use rustc_target::spec::abi::Abi;
use rustc_trait_selection::infer::{TyCtxtInferExt, ValuePairs};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
@@ -101,12 +100,11 @@ impl CheckAttrVisitor<'_> {
item: Option<ItemLike<'_>>,
) {
let mut doc_aliases = FxHashMap::default();
- let mut is_valid = true;
let mut specified_inline = None;
let mut seen = FxHashMap::default();
let attrs = self.tcx.hir().attrs(hir_id);
for attr in attrs {
- let attr_is_valid = match attr.name_or_empty() {
+ match attr.name_or_empty() {
sym::do_not_recommend => self.check_do_not_recommend(attr.span, target),
sym::inline => self.check_inline(hir_id, attr, span, target),
sym::no_coverage => self.check_no_coverage(hir_id, attr, span, target),
@@ -188,7 +186,6 @@ impl CheckAttrVisitor<'_> {
sym::link_ordinal => self.check_link_ordinal(&attr, span, target),
_ => true,
};
- is_valid &= attr_is_valid;
// lint-only checks
match attr.name_or_empty() {
@@ -255,10 +252,6 @@ impl CheckAttrVisitor<'_> {
self.check_unused_attribute(hir_id, attr)
}
- if !is_valid {
- return;
- }
-
self.check_repr(attrs, span, target, item, hir_id);
self.check_used(attrs, target);
}
@@ -927,30 +920,18 @@ impl CheckAttrVisitor<'_> {
hir_id: HirId,
) -> bool {
if hir_id != CRATE_HIR_ID {
- self.tcx.struct_span_lint_hir(
+ // insert a bang between `#` and `[...`
+ let bang_span = attr.span.lo() + BytePos(1);
+ let sugg = (attr.style == AttrStyle::Outer
+ && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID)
+ .then_some(errors::AttrCrateLevelOnlySugg {
+ attr: attr.span.with_lo(bang_span).with_hi(bang_span),
+ });
+ self.tcx.emit_spanned_lint(
INVALID_DOC_ATTRIBUTES,
hir_id,
meta.span(),
- fluent::passes_attr_crate_level,
- |err| {
- if attr.style == AttrStyle::Outer
- && self.tcx.hir().get_parent_item(hir_id) == CRATE_OWNER_ID
- {
- if let Ok(mut src) = self.tcx.sess.source_map().span_to_snippet(attr.span) {
- src.insert(1, '!');
- err.span_suggestion_verbose(
- attr.span,
- fluent::passes_suggestion,
- src,
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_help(attr.span, fluent::passes_help);
- }
- }
- err.note(fluent::passes_note);
- err
- },
+ errors::AttrCrateLevelOnly { sugg },
);
return false;
}
@@ -1728,7 +1709,9 @@ impl CheckAttrVisitor<'_> {
}
}
sym::align => {
- if let (Target::Fn, false) = (target, self.tcx.features().fn_align) {
+ if let (Target::Fn | Target::Method(MethodKind::Inherent), false) =
+ (target, self.tcx.features().fn_align)
+ {
feature_err(
&self.tcx.sess.parse_sess,
sym::fn_align,
@@ -1739,10 +1722,14 @@ impl CheckAttrVisitor<'_> {
}
match target {
- Target::Struct | Target::Union | Target::Enum | Target::Fn => continue,
+ Target::Struct
+ | Target::Union
+ | Target::Enum
+ | Target::Fn
+ | Target::Method(_) => continue,
_ => {
self.tcx.sess.emit_err(
- errors::AttrApplication::StructEnumFunctionUnion {
+ errors::AttrApplication::StructEnumFunctionMethodUnion {
hint_span: hint.span(),
span,
},
@@ -1829,7 +1816,7 @@ impl CheckAttrVisitor<'_> {
|| (is_simd && is_c)
|| (int_reprs == 1
&& is_c
- && item.map_or(false, |item| {
+ && item.is_some_and(|item| {
if let ItemLike::Item(item) = item {
return is_c_like_enum(item);
}
@@ -1928,6 +1915,10 @@ impl CheckAttrVisitor<'_> {
/// Checks if the items on the `#[debugger_visualizer]` attribute are valid.
fn check_debugger_visualizer(&self, attr: &Attribute, target: Target) -> bool {
+ // Here we only check that the #[debugger_visualizer] attribute is attached
+ // to nothing other than a module. All other checks are done in the
+ // `debugger_visualizer` query where they need to be done for decoding
+ // anyway.
match target {
Target::Mod => {}
_ => {
@@ -1936,53 +1927,7 @@ impl CheckAttrVisitor<'_> {
}
}
- let Some(hints) = attr.meta_item_list() else {
- self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
- return false;
- };
-
- let hint = match hints.len() {
- 1 => &hints[0],
- _ => {
- self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
- return false;
- }
- };
-
- let Some(meta_item) = hint.meta_item() else {
- self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: attr.span });
- return false;
- };
-
- let visualizer_path = match (meta_item.name_or_empty(), meta_item.value_str()) {
- (sym::natvis_file, Some(value)) => value,
- (sym::gdb_script_file, Some(value)) => value,
- (_, _) => {
- self.tcx.sess.emit_err(errors::DebugVisualizerInvalid { span: meta_item.span });
- return false;
- }
- };
-
- let file =
- match resolve_path(&self.tcx.sess.parse_sess, visualizer_path.as_str(), attr.span) {
- Ok(file) => file,
- Err(mut err) => {
- err.emit();
- return false;
- }
- };
-
- match std::fs::File::open(&file) {
- Ok(_) => true,
- Err(error) => {
- self.tcx.sess.emit_err(errors::DebugVisualizerUnreadable {
- span: meta_item.span,
- file: &file,
- error,
- });
- false
- }
- }
+ true
}
/// Outputs an error for `#[allow_internal_unstable]` which can only be applied to macros.
@@ -2150,7 +2095,7 @@ impl CheckAttrVisitor<'_> {
| sym::feature
| sym::repr
| sym::target_feature
- ) && attr.meta_item_list().map_or(false, |list| list.is_empty())
+ ) && attr.meta_item_list().is_some_and(|list| list.is_empty())
{
errors::UnusedNote::EmptyList { name: attr.name_or_empty() }
} else if matches!(
diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs
index 30dd3e4d0..2357b0aad 100644
--- a/compiler/rustc_passes/src/check_const.rs
+++ b/compiler/rustc_passes/src/check_const.rs
@@ -12,7 +12,7 @@ use rustc_hir as hir;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::parse::feature_err;
use rustc_span::{sym, Span, Symbol};
@@ -148,7 +148,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
[missing_primary, ref missing_secondary @ ..] => {
let msg =
format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name());
- let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg);
+ let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, msg);
// If multiple feature gates would be required to enable this expression, include
// them as help messages. Don't emit a separate error for each missing feature gate.
@@ -161,7 +161,7 @@ impl<'tcx> CheckConstVisitor<'tcx> {
"add `#![feature({})]` to the crate attributes to enable",
gate,
);
- err.help(&note);
+ err.help(note);
}
}
diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs
index 5cfe691df..7812dcde4 100644
--- a/compiler/rustc_passes/src/dead.rs
+++ b/compiler/rustc_passes/src/dead.rs
@@ -12,7 +12,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Node, PatKind, TyKind};
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::privacy::Level;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{sym, Symbol};
@@ -237,6 +237,37 @@ impl<'tcx> MarkSymbolVisitor<'tcx> {
}
}
+ fn handle_offset_of(&mut self, expr: &'tcx hir::Expr<'tcx>) {
+ let data = self.typeck_results().offset_of_data();
+ let &(container, ref indices) =
+ data.get(expr.hir_id).expect("no offset_of_data for offset_of");
+
+ let body_did = self.typeck_results().hir_owner.to_def_id();
+ let param_env = self.tcx.param_env(body_did);
+
+ let mut current_ty = container;
+
+ for &index in indices {
+ match current_ty.kind() {
+ ty::Adt(def, subst) => {
+ let field = &def.non_enum_variant().fields[index];
+
+ self.insert_def_id(field.did);
+ let field_ty = field.ty(self.tcx, subst);
+
+ current_ty = self.tcx.normalize_erasing_regions(param_env, field_ty);
+ }
+ // we don't need to mark tuple fields as live,
+ // but we may need to mark subfields
+ ty::Tuple(tys) => {
+ current_ty =
+ self.tcx.normalize_erasing_regions(param_env, tys[index.as_usize()]);
+ }
+ _ => span_bug!(expr.span, "named field access on non-ADT"),
+ }
+ }
+ }
+
fn mark_live_symbols(&mut self) {
let mut scanned = LocalDefIdSet::default();
while let Some(id) = self.worklist.pop() {
@@ -405,6 +436,9 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> {
hir::ExprKind::Closure(cls) => {
self.insert_def_id(cls.def_id.to_def_id());
}
+ hir::ExprKind::OffsetOf(..) => {
+ self.handle_offset_of(expr);
+ }
_ => (),
}
diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs
index 9dd39a5c9..3483f7da5 100644
--- a/compiler/rustc_passes/src/debugger_visualizer.rs
+++ b/compiler/rustc_passes/src/debugger_visualizer.rs
@@ -1,61 +1,69 @@
//! Detecting usage of the `#[debugger_visualizer]` attribute.
-use hir::CRATE_HIR_ID;
-use rustc_data_structures::fx::FxHashSet;
+use rustc_ast::Attribute;
+use rustc_data_structures::sync::Lrc;
use rustc_expand::base::resolve_path;
-use rustc_hir as hir;
-use rustc_hir::HirId;
-use rustc_middle::ty::TyCtxt;
-use rustc_middle::{query::LocalCrate, ty::query::Providers};
-use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType};
+use rustc_middle::{
+ middle::debugger_visualizer::{DebuggerVisualizerFile, DebuggerVisualizerType},
+ query::{LocalCrate, Providers},
+ ty::TyCtxt,
+};
+use rustc_session::Session;
+use rustc_span::sym;
-use std::sync::Arc;
+use crate::errors::{DebugVisualizerInvalid, DebugVisualizerUnreadable};
-use crate::errors::DebugVisualizerUnreadable;
-
-fn check_for_debugger_visualizer(
- tcx: TyCtxt<'_>,
- hir_id: HirId,
- debugger_visualizers: &mut FxHashSet<DebuggerVisualizerFile>,
-) {
- let attrs = tcx.hir().attrs(hir_id);
- for attr in attrs {
+impl DebuggerVisualizerCollector<'_> {
+ fn check_for_debugger_visualizer(&mut self, attr: &Attribute) {
if attr.has_name(sym::debugger_visualizer) {
- let Some(list) = attr.meta_item_list() else {
- continue
+ let Some(hints) = attr.meta_item_list() else {
+ self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+ return;
};
- let meta_item = match list.len() {
- 1 => match list[0].meta_item() {
- Some(meta_item) => meta_item,
- _ => continue,
- },
- _ => continue,
+ let hint = if hints.len() == 1 {
+ &hints[0]
+ } else {
+ self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+ return;
};
- let visualizer_type = match meta_item.name_or_empty() {
- sym::natvis_file => DebuggerVisualizerType::Natvis,
- sym::gdb_script_file => DebuggerVisualizerType::GdbPrettyPrinter,
- _ => continue,
+ let Some(meta_item) = hint.meta_item() else {
+ self.sess.emit_err(DebugVisualizerInvalid { span: attr.span });
+ return;
};
- let file = match meta_item.value_str() {
- Some(value) => {
- match resolve_path(&tcx.sess.parse_sess, value.as_str(), attr.span) {
- Ok(file) => file,
- _ => continue,
+ let (visualizer_type, visualizer_path) =
+ match (meta_item.name_or_empty(), meta_item.value_str()) {
+ (sym::natvis_file, Some(value)) => (DebuggerVisualizerType::Natvis, value),
+ (sym::gdb_script_file, Some(value)) => {
+ (DebuggerVisualizerType::GdbPrettyPrinter, value)
}
- }
- None => continue,
- };
+ (_, _) => {
+ self.sess.emit_err(DebugVisualizerInvalid { span: meta_item.span });
+ return;
+ }
+ };
+
+ let file =
+ match resolve_path(&self.sess.parse_sess, visualizer_path.as_str(), attr.span) {
+ Ok(file) => file,
+ Err(mut err) => {
+ err.emit();
+ return;
+ }
+ };
match std::fs::read(&file) {
Ok(contents) => {
- debugger_visualizers
- .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type));
+ self.visualizers.push(DebuggerVisualizerFile::new(
+ Lrc::from(contents),
+ visualizer_type,
+ file,
+ ));
}
Err(error) => {
- tcx.sess.emit_err(DebugVisualizerUnreadable {
+ self.sess.emit_err(DebugVisualizerUnreadable {
span: meta_item.span,
file: &file,
error,
@@ -66,29 +74,30 @@ fn check_for_debugger_visualizer(
}
}
-/// Traverses and collects the debugger visualizers for a specific crate.
-fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
- // Initialize the collector.
- let mut debugger_visualizers = FxHashSet::default();
+struct DebuggerVisualizerCollector<'a> {
+ sess: &'a Session,
+ visualizers: Vec<DebuggerVisualizerFile>,
+}
- // Collect debugger visualizers in this crate.
- tcx.hir().for_each_module(|id| {
- check_for_debugger_visualizer(
- tcx,
- tcx.hir().local_def_id_to_hir_id(id),
- &mut debugger_visualizers,
- )
- });
+impl<'ast> rustc_ast::visit::Visitor<'ast> for DebuggerVisualizerCollector<'_> {
+ fn visit_attribute(&mut self, attr: &'ast Attribute) {
+ self.check_for_debugger_visualizer(attr);
+ rustc_ast::visit::walk_attribute(self, attr);
+ }
+}
- // Collect debugger visualizers on the crate attributes.
- check_for_debugger_visualizer(tcx, CRATE_HIR_ID, &mut debugger_visualizers);
+/// Traverses and collects the debugger visualizers for a specific crate.
+fn debugger_visualizers(tcx: TyCtxt<'_>, _: LocalCrate) -> Vec<DebuggerVisualizerFile> {
+ let resolver_and_krate = tcx.resolver_for_lowering(()).borrow();
+ let krate = &*resolver_and_krate.1;
- // Extract out the found debugger_visualizer items.
- let mut visualizers = debugger_visualizers.into_iter().collect::<Vec<_>>();
+ let mut visitor = DebuggerVisualizerCollector { sess: tcx.sess, visualizers: Vec::new() };
+ rustc_ast::visit::Visitor::visit_crate(&mut visitor, krate);
- // Sort the visualizers so we always get a deterministic query result.
- visualizers.sort();
- visualizers
+ // We are collecting visualizers in AST-order, which is deterministic,
+ // so we don't need to do any explicit sorting in order to get a
+ // deterministic query result
+ visitor.visualizers
}
pub fn provide(providers: &mut Providers) {
diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs
index eb6ea673c..d8b9f4fae 100644
--- a/compiler/rustc_passes/src/diagnostic_items.rs
+++ b/compiler/rustc_passes/src/diagnostic_items.rs
@@ -13,7 +13,7 @@ use rustc_ast as ast;
use rustc_hir::diagnostic_items::DiagnosticItems;
use rustc_hir::OwnerId;
use rustc_middle::query::LocalCrate;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::def_id::{DefId, LOCAL_CRATE};
use rustc_span::symbol::{sym, Symbol};
diff --git a/compiler/rustc_passes/src/entry.rs b/compiler/rustc_passes/src/entry.rs
index e3e4b73ef..ffd8f77b7 100644
--- a/compiler/rustc_passes/src/entry.rs
+++ b/compiler/rustc_passes/src/entry.rs
@@ -4,7 +4,7 @@ use rustc_errors::error_code;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{ItemId, Node, CRATE_HIR_ID};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::config::{sigpipe, CrateType, EntryFnType};
use rustc_session::parse::feature_err;
diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs
index 139ba8c96..99fc69d1b 100644
--- a/compiler/rustc_passes/src/errors.rs
+++ b/compiler/rustc_passes/src/errors.rs
@@ -6,7 +6,8 @@ use std::{
use crate::fluent_generated as fluent;
use rustc_ast::Label;
use rustc_errors::{
- error_code, Applicability, DiagnosticSymbolList, ErrorGuaranteed, IntoDiagnostic, MultiSpan,
+ error_code, AddToDiagnostic, Applicability, Diagnostic, DiagnosticSymbolList, ErrorGuaranteed,
+ IntoDiagnostic, MultiSpan,
};
use rustc_hir::{self as hir, ExprKind, Target};
use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic};
@@ -1355,8 +1356,8 @@ pub enum AttrApplication {
#[label]
span: Span,
},
- #[diag(passes_attr_application_struct_enum_function_union, code = "E0517")]
- StructEnumFunctionUnion {
+ #[diag(passes_attr_application_struct_enum_function_method_union, code = "E0517")]
+ StructEnumFunctionMethodUnion {
#[primary_span]
hint_span: Span,
#[label]
@@ -1555,3 +1556,160 @@ pub struct SkippingConstChecks {
#[primary_span]
pub span: Span,
}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unreachable_due_to_uninhabited)]
+pub struct UnreachableDueToUninhabited<'desc, 'tcx> {
+ pub descr: &'desc str,
+ #[label]
+ pub expr: Span,
+ #[label(passes_label_orig)]
+ #[note]
+ pub orig: Span,
+ pub ty: Ty<'tcx>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_maybe_capture_ref)]
+#[help]
+pub struct UnusedVarMaybeCaptureRef {
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_capture_maybe_capture_ref)]
+#[help]
+pub struct UnusedCaptureMaybeCaptureRef {
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_remove_field)]
+pub struct UnusedVarRemoveField {
+ pub name: String,
+ #[subdiagnostic]
+ pub sugg: UnusedVarRemoveFieldSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(
+ passes_unused_var_remove_field_suggestion,
+ applicability = "machine-applicable"
+)]
+pub struct UnusedVarRemoveFieldSugg {
+ #[suggestion_part(code = "")]
+ pub spans: Vec<Span>,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_var_assigned_only)]
+#[note]
+pub struct UnusedVarAssignedOnly {
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unnecessary_stable_feature)]
+pub struct UnnecessaryStableFeature {
+ pub feature: Symbol,
+ pub since: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unnecessary_partial_stable_feature)]
+pub struct UnnecessaryPartialStableFeature {
+ #[suggestion(code = "{implies}", applicability = "maybe-incorrect")]
+ pub span: Span,
+ #[suggestion(passes_suggestion_remove, code = "", applicability = "maybe-incorrect")]
+ pub line: Span,
+ pub feature: Symbol,
+ pub since: Symbol,
+ pub implies: Symbol,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_ineffective_unstable_impl)]
+#[note]
+pub struct IneffectiveUnstableImpl;
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_assign)]
+#[help]
+pub struct UnusedAssign {
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_assign_passed)]
+#[help]
+pub struct UnusedAssignPassed {
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_variable_try_prefix)]
+pub struct UnusedVariableTryPrefix {
+ #[label]
+ pub label: Option<Span>,
+ #[subdiagnostic]
+ pub string_interp: Vec<UnusedVariableStringInterp>,
+ #[subdiagnostic]
+ pub sugg: UnusedVariableTryPrefixSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+pub struct UnusedVariableTryPrefixSugg {
+ #[suggestion_part(code = "_{name}")]
+ pub spans: Vec<Span>,
+ pub name: String,
+}
+
+pub struct UnusedVariableStringInterp {
+ pub lit: Span,
+ pub lo: Span,
+ pub hi: Span,
+}
+
+impl AddToDiagnostic for UnusedVariableStringInterp {
+ fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, _: F) {
+ diag.span_label(self.lit, crate::fluent_generated::passes_maybe_string_interpolation);
+ diag.multipart_suggestion(
+ crate::fluent_generated::passes_string_interpolation_only_works,
+ vec![(self.lo, String::from("format!(")), (self.hi, String::from(")"))],
+ Applicability::MachineApplicable,
+ );
+ }
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_unused_variable_try_ignore)]
+pub struct UnusedVarTryIgnore {
+ #[subdiagnostic]
+ pub sugg: UnusedVarTryIgnoreSugg,
+}
+
+#[derive(Subdiagnostic)]
+#[multipart_suggestion(passes_suggestion, applicability = "machine-applicable")]
+pub struct UnusedVarTryIgnoreSugg {
+ #[suggestion_part(code = "{name}: _")]
+ pub shorthands: Vec<Span>,
+ #[suggestion_part(code = "_")]
+ pub non_shorthands: Vec<Span>,
+ pub name: String,
+}
+
+#[derive(LintDiagnostic)]
+#[diag(passes_attr_crate_level)]
+#[note]
+pub struct AttrCrateLevelOnly {
+ #[subdiagnostic]
+ pub sugg: Option<AttrCrateLevelOnlySugg>,
+}
+
+#[derive(Subdiagnostic)]
+#[suggestion(passes_suggestion, applicability = "maybe-incorrect", code = "!", style = "verbose")]
+pub struct AttrCrateLevelOnlySugg {
+ #[primary_span]
+ pub attr: Span,
+}
diff --git a/compiler/rustc_passes/src/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs
index 3942a73be..363e17436 100644
--- a/compiler/rustc_passes/src/hir_id_validator.rs
+++ b/compiler/rustc_passes/src/hir_id_validator.rs
@@ -31,7 +31,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) {
if !errors.is_empty() {
let message = errors.iter().fold(String::new(), |s1, s2| s1 + "\n" + s2);
- tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, &message);
+ tcx.sess.delay_span_bug(rustc_span::DUMMY_SP, message);
}
}
}
diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs
index 47e032758..dc5e45407 100644
--- a/compiler/rustc_passes/src/hir_stats.rs
+++ b/compiler/rustc_passes/src/hir_stats.rs
@@ -302,7 +302,8 @@ impl<'v> hir_visit::Visitor<'v> for StatCollector<'v> {
[
ConstBlock, Array, Call, MethodCall, Tup, Binary, Unary, Lit, Cast, Type,
DropTemps, Let, If, Loop, Match, Closure, Block, Assign, AssignOp, Field, Index,
- Path, AddrOf, Break, Continue, Ret, InlineAsm, Struct, Repeat, Yield, Err
+ Path, AddrOf, Break, Continue, Ret, InlineAsm, OffsetOf, Struct, Repeat, Yield,
+ Err
]
);
hir_visit::walk_expr(self, e)
@@ -568,7 +569,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> {
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, FormatArgs, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
+ InlineAsm, FormatArgs, OffsetOf, MacCall, Struct, Repeat, Paren, Try, Yield, Yeet, IncludedBytes, Err
]
);
ast_visit::walk_expr(self, e)
diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs
index fdd0e5dab..476394f30 100644
--- a/compiler/rustc_passes/src/lang_items.rs
+++ b/compiler/rustc_passes/src/lang_items.rs
@@ -22,7 +22,7 @@ use rustc_middle::ty::TyCtxt;
use rustc_session::cstore::ExternCrate;
use rustc_span::{symbol::kw::Empty, Span};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
pub(crate) enum Duplicate {
Plain,
diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs
index b7e07aff4..0da4b2946 100644
--- a/compiler/rustc_passes/src/lib.rs
+++ b/compiler/rustc_passes/src/lib.rs
@@ -12,6 +12,8 @@
#![feature(min_specialization)]
#![feature(try_blocks)]
#![recursion_limit = "256"]
+#![deny(rustc::untranslatable_diagnostic)]
+#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
extern crate rustc_middle;
@@ -19,8 +21,8 @@ extern crate rustc_middle;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
-use rustc_middle::ty::query::Providers;
+use rustc_fluent_macro::fluent_messages;
+use rustc_middle::query::Providers;
mod check_attr;
mod check_const;
diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs
index f4da1aaec..44174b1b8 100644
--- a/compiler/rustc_passes/src/lib_features.rs
+++ b/compiler/rustc_passes/src/lib_features.rs
@@ -9,7 +9,7 @@ use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER};
use rustc_hir::intravisit::Visitor;
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::lib_features::LibFeatures;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::symbol::Symbol;
use rustc_span::{sym, Span};
diff --git a/compiler/rustc_passes/src/liveness.rs b/compiler/rustc_passes/src/liveness.rs
index a8471ce3b..63b1578d4 100644
--- a/compiler/rustc_passes/src/liveness.rs
+++ b/compiler/rustc_passes/src/liveness.rs
@@ -81,23 +81,24 @@
//! We generate various special nodes for various, well, special purposes.
//! These are described in the `Liveness` struct.
+use crate::errors;
+
use self::LiveNodeKind::*;
use self::VarKind::*;
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};
+use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet};
-use rustc_index::vec::IndexVec;
-use rustc_middle::ty::query::Providers;
+use rustc_index::IndexVec;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, RootVariableMinCaptureList, Ty, TyCtxt};
use rustc_session::lint;
use rustc_span::symbol::{kw, sym, Symbol};
+use rustc_span::DUMMY_SP;
use rustc_span::{BytePos, Span};
use std::collections::VecDeque;
@@ -137,14 +138,9 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String {
}
}
-fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) {
- let local_def_id = match def_id.as_local() {
- None => return,
- Some(def_id) => def_id,
- };
-
+fn check_liveness(tcx: TyCtxt<'_>, def_id: LocalDefId) {
// Don't run unused pass for #[derive()]
- let parent = tcx.local_parent(local_def_id);
+ let parent = tcx.local_parent(def_id);
if let DefKind::Impl { .. } = tcx.def_kind(parent)
&& tcx.has_attr(parent, sym::automatically_derived)
{
@@ -152,12 +148,12 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) {
}
// Don't run unused pass for #[naked]
- if tcx.has_attr(def_id, sym::naked) {
+ if tcx.has_attr(def_id.to_def_id(), sym::naked) {
return;
}
let mut maps = IrMaps::new(tcx);
- let body_id = tcx.hir().body_owned_by(local_def_id);
+ let body_id = tcx.hir().body_owned_by(def_id);
let hir_id = tcx.hir().body_owner(body_id);
let body = tcx.hir().body(body_id);
@@ -173,7 +169,7 @@ fn check_liveness(tcx: TyCtxt<'_>, def_id: DefId) {
maps.visit_body(body);
// compute liveness
- let mut lsets = Liveness::new(&mut maps, local_def_id);
+ let mut lsets = Liveness::new(&mut maps, def_id);
let entry_ln = lsets.compute(&body, hir_id);
lsets.log_liveness(entry_ln, body_id.hir_id);
@@ -331,7 +327,7 @@ impl<'tcx> IrMaps<'tcx> {
pats.extend(inner_pat.iter());
}
Struct(_, fields, _) => {
- let (short, not_short): (Vec<_>, _) =
+ let (short, not_short): (Vec<hir::PatField<'_>>, _) =
fields.iter().partition(|f| f.is_shorthand);
shorthand_field_ids.extend(short.iter().map(|f| f.pat.hir_id));
pats.extend(not_short.iter().map(|f| f.pat));
@@ -473,6 +469,7 @@ impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> {
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::InlineAsm(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Type(..)
| hir::ExprKind::Err(_)
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
@@ -591,8 +588,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
}
fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> bool {
- let successor = self.successors[ln].unwrap();
- self.assigned_on_entry(successor, var)
+ match self.successors[ln] {
+ Some(successor) => self.assigned_on_entry(successor, var),
+ None => {
+ self.ir.tcx.sess.delay_span_bug(DUMMY_SP, "no successor");
+ true
+ }
+ }
}
fn write_vars<F>(&self, wr: &mut dyn Write, mut test: F) -> io::Result<()>
@@ -1129,7 +1131,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Err(_)
| hir::ExprKind::Path(hir::QPath::TypeRelative(..))
- | hir::ExprKind::Path(hir::QPath::LangItem(..)) => succ,
+ | hir::ExprKind::Path(hir::QPath::LangItem(..))
+ | hir::ExprKind::OffsetOf(..) => succ,
// Note that labels have been resolved, so we don't need to look
// at the label ident
@@ -1294,13 +1297,13 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
self.exit_ln
}
- fn warn_about_unreachable(
+ fn warn_about_unreachable<'desc>(
&mut self,
orig_span: Span,
orig_ty: Ty<'tcx>,
expr_span: Span,
expr_id: HirId,
- descr: &str,
+ descr: &'desc str,
) {
if !orig_ty.is_never() {
// Unreachable code warnings are already emitted during type checking.
@@ -1313,22 +1316,15 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> {
// that we do not emit the same warning twice if the uninhabited type
// is indeed `!`.
- let msg = format!("unreachable {}", descr);
- self.ir.tcx.struct_span_lint_hir(
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNREACHABLE_CODE,
expr_id,
expr_span,
- &msg,
- |diag| {
- diag.span_label(expr_span, &msg)
- .span_label(orig_span, "any code following this expression is unreachable")
- .span_note(
- orig_span,
- &format!(
- "this expression has type `{}`, which is uninhabited",
- orig_ty
- ),
- )
+ errors::UnreachableDueToUninhabited {
+ expr: expr_span,
+ orig: orig_span,
+ descr,
+ ty: orig_ty,
},
);
}
@@ -1418,6 +1414,7 @@ fn check_expr<'tcx>(this: &mut Liveness<'_, 'tcx>, expr: &'tcx Expr<'tcx>) {
| hir::ExprKind::ConstBlock(..)
| hir::ExprKind::Block(..)
| hir::ExprKind::AddrOf(..)
+ | hir::ExprKind::OffsetOf(..)
| hir::ExprKind::Struct(..)
| hir::ExprKind::Repeat(..)
| hir::ExprKind::Closure { .. }
@@ -1479,23 +1476,21 @@ impl<'tcx> Liveness<'_, 'tcx> {
if self.used_on_entry(entry_ln, var) {
if !self.live_on_entry(entry_ln, var) {
if let Some(name) = self.should_warn(var) {
- self.ir.tcx.struct_span_lint_hir(
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_ASSIGNMENTS,
var_hir_id,
vec![span],
- format!("value captured by `{}` is never read", name),
- |lint| lint.help("did you mean to capture by reference instead?"),
+ errors::UnusedCaptureMaybeCaptureRef { name },
);
}
}
} else {
if let Some(name) = self.should_warn(var) {
- self.ir.tcx.struct_span_lint_hir(
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
var_hir_id,
vec![span],
- format!("unused variable: `{}`", name),
- |lint| lint.help("did you mean to capture by reference instead?"),
+ errors::UnusedVarMaybeCaptureRef { name },
);
}
}
@@ -1510,11 +1505,14 @@ impl<'tcx> Liveness<'_, 'tcx> {
Some(entry_ln),
Some(body),
|spans, hir_id, ln, var| {
- if !self.live_on_entry(ln, var) {
- self.report_unused_assign(hir_id, spans, var, |name| {
- format!("value passed to `{}` is never read", name)
- });
- }
+ if !self.live_on_entry(ln, var)
+ && let Some(name) = self.should_warn(var) {
+ self.ir.tcx.emit_spanned_lint(
+ lint::builtin::UNUSED_ASSIGNMENTS,
+ hir_id,
+ spans,
+ errors::UnusedAssignPassed { name },
+ ); }
},
);
}
@@ -1583,39 +1581,35 @@ impl<'tcx> Liveness<'_, 'tcx> {
if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var) };
if is_assigned {
- self.ir.tcx.struct_span_lint_hir(
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans
.into_iter()
.map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>(),
- format!("variable `{}` is assigned to, but never used", name),
- |lint| lint.note(&format!("consider using `_{}` instead", name)),
+ errors::UnusedVarAssignedOnly { name },
)
} else if can_remove {
- self.ir.tcx.struct_span_lint_hir(
+ let spans = hir_ids_and_spans
+ .iter()
+ .map(|(_, pat_span, _)| {
+ let span = self
+ .ir
+ .tcx
+ .sess
+ .source_map()
+ .span_extend_to_next_char(*pat_span, ',', true);
+ span.with_hi(BytePos(span.hi().0 + 1))
+ })
+ .collect();
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans.iter().map(|(_, pat_span, _)| *pat_span).collect::<Vec<_>>(),
- format!("unused variable: `{}`", name),
- |lint| {
- lint.multipart_suggestion(
- "try removing the field",
- hir_ids_and_spans
- .iter()
- .map(|(_, pat_span, _)| {
- let span = self
- .ir
- .tcx
- .sess
- .source_map()
- .span_extend_to_next_char(*pat_span, ',', true);
- (span.with_hi(BytePos(span.hi().0 + 1)), String::new())
- })
- .collect(),
- Applicability::MachineApplicable,
- )
+ errors::UnusedVarRemoveField {
+ name,
+ sugg: errors::UnusedVarRemoveFieldSugg { spans },
},
);
} else {
@@ -1629,55 +1623,46 @@ impl<'tcx> Liveness<'_, 'tcx> {
// the field" message, and suggest `_` for the non-shorthands. If we only
// have non-shorthand, then prefix with an underscore instead.
if !shorthands.is_empty() {
- let shorthands = shorthands
- .into_iter()
- .map(|(_, pat_span, _)| (pat_span, format!("{}: _", name)))
- .chain(
- non_shorthands
- .into_iter()
- .map(|(_, pat_span, _)| (pat_span, "_".to_string())),
- )
- .collect::<Vec<_>>();
+ let shorthands =
+ shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect();
+ let non_shorthands =
+ non_shorthands.into_iter().map(|(_, pat_span, _)| pat_span).collect();
- self.ir.tcx.struct_span_lint_hir(
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans
.iter()
.map(|(_, pat_span, _)| *pat_span)
.collect::<Vec<_>>(),
- format!("unused variable: `{}`", name),
- |lint| {
- lint.multipart_suggestion(
- "try ignoring the field",
+ errors::UnusedVarTryIgnore {
+ sugg: errors::UnusedVarTryIgnoreSugg {
shorthands,
- Applicability::MachineApplicable,
- )
+ non_shorthands,
+ name,
+ },
},
);
} else {
let non_shorthands = non_shorthands
.into_iter()
- .map(|(_, _, ident_span)| (ident_span, format!("_{}", name)))
+ .map(|(_, _, ident_span)| ident_span)
.collect::<Vec<_>>();
-
- self.ir.tcx.struct_span_lint_hir(
+ let suggestions = self.string_interp_suggestions(&name, opt_body);
+ self.ir.tcx.emit_spanned_lint(
lint::builtin::UNUSED_VARIABLES,
first_hir_id,
hir_ids_and_spans
.iter()
.map(|(_, _, ident_span)| *ident_span)
.collect::<Vec<_>>(),
- format!("unused variable: `{}`", name),
- |lint| {
- if self.has_added_lit_match_name_span(&name, opt_body, lint) {
- lint.span_label(pat.span, "unused variable");
- }
- lint.multipart_suggestion(
- "if this is intentional, prefix it with an underscore",
- non_shorthands,
- Applicability::MachineApplicable,
- )
+ errors::UnusedVariableTryPrefix {
+ label: if !suggestions.is_empty() { Some(pat.span) } else { None },
+ sugg: errors::UnusedVariableTryPrefixSugg {
+ spans: non_shorthands,
+ name,
+ },
+ string_interp: suggestions,
},
);
}
@@ -1685,65 +1670,40 @@ impl<'tcx> Liveness<'_, 'tcx> {
}
}
- fn has_added_lit_match_name_span(
+ fn string_interp_suggestions(
&self,
name: &str,
opt_body: Option<&hir::Body<'_>>,
- err: &mut Diagnostic,
- ) -> bool {
- let mut has_litstring = false;
- let Some(opt_body) = opt_body else {return false;};
+ ) -> Vec<errors::UnusedVariableStringInterp> {
+ let mut suggs = Vec::new();
+ let Some(opt_body) = opt_body else { return suggs; };
let mut visitor = CollectLitsVisitor { lit_exprs: vec![] };
intravisit::walk_body(&mut visitor, opt_body);
for lit_expr in visitor.lit_exprs {
let hir::ExprKind::Lit(litx) = &lit_expr.kind else { continue };
let rustc_ast::LitKind::Str(syb, _) = litx.node else{ continue; };
let name_str: &str = syb.as_str();
- let mut name_pa = String::from("{");
- name_pa.push_str(&name);
- name_pa.push('}');
+ let name_pa = format!("{{{name}}}");
if name_str.contains(&name_pa) {
- err.span_label(
- lit_expr.span,
- "you might have meant to use string interpolation in this string literal",
- );
- err.multipart_suggestion(
- "string interpolation only works in `format!` invocations",
- vec![
- (lit_expr.span.shrink_to_lo(), "format!(".to_string()),
- (lit_expr.span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MachineApplicable,
- );
- has_litstring = true;
+ suggs.push(errors::UnusedVariableStringInterp {
+ lit: lit_expr.span,
+ lo: lit_expr.span.shrink_to_lo(),
+ hi: lit_expr.span.shrink_to_hi(),
+ });
}
}
- has_litstring
+ suggs
}
fn warn_about_dead_assign(&self, spans: Vec<Span>, hir_id: HirId, ln: LiveNode, var: Variable) {
- if !self.live_on_exit(ln, var) {
- self.report_unused_assign(hir_id, spans, var, |name| {
- format!("value assigned to `{}` is never read", name)
- });
- }
- }
-
- fn report_unused_assign(
- &self,
- hir_id: HirId,
- spans: Vec<Span>,
- var: Variable,
- message: impl Fn(&str) -> String,
- ) {
- if let Some(name) = self.should_warn(var) {
- self.ir.tcx.struct_span_lint_hir(
- lint::builtin::UNUSED_ASSIGNMENTS,
- hir_id,
- spans,
- message(&name),
- |lint| lint.help("maybe it is overwritten before being read?"),
- )
- }
+ if !self.live_on_exit(ln, var)
+ && let Some(name) = self.should_warn(var) {
+ self.ir.tcx.emit_spanned_lint(
+ lint::builtin::UNUSED_ASSIGNMENTS,
+ hir_id,
+ spans,
+ errors::UnusedAssign { name },
+ );
+ }
}
}
diff --git a/compiler/rustc_passes/src/loops.rs b/compiler/rustc_passes/src/loops.rs
index b4cf19e4a..73cfe68e7 100644
--- a/compiler/rustc_passes/src/loops.rs
+++ b/compiler/rustc_passes/src/loops.rs
@@ -6,7 +6,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{Destination, Movability, Node};
use rustc_middle::hir::map::Map;
use rustc_middle::hir::nested_filter;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::Session;
use rustc_span::hygiene::DesugaringKind;
diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs
index c398467f0..a849d61ed 100644
--- a/compiler/rustc_passes/src/naked_functions.rs
+++ b/compiler/rustc_passes/src/naked_functions.rs
@@ -6,7 +6,7 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_hir::intravisit::Visitor;
use rustc_hir::{ExprKind, InlineAsmOperand, StmtKind};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_session::lint::builtin::UNDEFINED_NAKED_FUNCTION_ABI;
use rustc_span::symbol::sym;
@@ -203,6 +203,7 @@ impl<'tcx> CheckInlineAssembly<'tcx> {
| ExprKind::Break(..)
| ExprKind::Continue(..)
| ExprKind::Ret(..)
+ | ExprKind::OffsetOf(..)
| ExprKind::Struct(..)
| ExprKind::Repeat(..)
| ExprKind::Yield(..) => {
diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs
index a5f7b07fe..160528e40 100644
--- a/compiler/rustc_passes/src/reachable.rs
+++ b/compiler/rustc_passes/src/reachable.rs
@@ -13,7 +13,7 @@ use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::Node;
use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs};
use rustc_middle::middle::privacy::{self, Level};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, TyCtxt};
use rustc_session::config::CrateType;
use rustc_target::spec::abi::Abi;
diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs
index 4a35c6794..b81b7ad60 100644
--- a/compiler/rustc_passes/src/stability.rs
+++ b/compiler/rustc_passes/src/stability.rs
@@ -7,7 +7,6 @@ use rustc_attr::{
UnstableReason, VERSION_PLACEHOLDER,
};
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
-use rustc_errors::Applicability;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID};
@@ -17,7 +16,8 @@ use rustc_hir::{FieldDef, Item, ItemKind, TraitRef, Ty, TyKind, Variant};
use rustc_middle::hir::nested_filter;
use rustc_middle::middle::privacy::EffectiveVisibilities;
use rustc_middle::middle::stability::{AllowUnstable, DeprecationEntry, Index};
-use rustc_middle::ty::{query::Providers, TyCtxt};
+use rustc_middle::query::Providers;
+use rustc_middle::ty::TyCtxt;
use rustc_session::lint;
use rustc_session::lint::builtin::{INEFFECTIVE_UNSTABLE_TRAIT_IMPL, USELESS_DEPRECATED};
use rustc_span::symbol::{sym, Symbol};
@@ -554,10 +554,8 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> {
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
- .tcx
- .lookup_stability(def_id)
- .map_or(false, |stability| stability.level.is_stable());
+ let is_stable =
+ self.tcx.lookup_stability(def_id).is_some_and(|stability| stability.level.is_stable());
let missing_const_stability_attribute = self.tcx.lookup_const_stability(def_id).is_none();
let is_reachable = self.effective_visibilities.is_reachable(def_id);
@@ -759,12 +757,11 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// do not lint when the trait isn't resolved, since resolution error should
// be fixed first
if t.path.res != Res::Err && c.fully_stable {
- self.tcx.struct_span_lint_hir(
+ self.tcx.emit_spanned_lint(
INEFFECTIVE_UNSTABLE_TRAIT_IMPL,
item.hir_id(),
span,
- "an `#[unstable]` annotation here has no effect",
- |lint| lint.note("see issue #55436 <https://github.com/rust-lang/rust/issues/55436> for more information")
+ errors::IneffectiveUnstableImpl,
);
}
}
@@ -773,7 +770,7 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
// needs to have an error emitted.
if features.const_trait_impl
&& *constness == hir::Constness::Const
- && const_stab.map_or(false, |(stab, _)| stab.is_const_stable())
+ && const_stab.is_some_and(|(stab, _)| stab.is_const_stable())
{
self.tcx.sess.emit_err(errors::TraitImplConstStable { span: item.span });
}
@@ -810,15 +807,12 @@ impl<'tcx> Visitor<'tcx> for Checker<'tcx> {
);
let is_allowed_through_unstable_modules = |def_id| {
- self.tcx
- .lookup_stability(def_id)
- .map(|stab| match stab.level {
- StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
- allowed_through_unstable_modules
- }
- _ => false,
- })
- .unwrap_or(false)
+ self.tcx.lookup_stability(def_id).is_some_and(|stab| match stab.level {
+ StabilityLevel::Stable { allowed_through_unstable_modules, .. } => {
+ allowed_through_unstable_modules
+ }
+ _ => false,
+ })
};
if item_is_allowed && !is_allowed_through_unstable_modules(def_id) {
@@ -1095,29 +1089,16 @@ fn unnecessary_partially_stable_feature_lint(
implies: Symbol,
since: Symbol,
) {
- tcx.struct_span_lint_hir(
+ tcx.emit_spanned_lint(
lint::builtin::STABLE_FEATURES,
hir::CRATE_HIR_ID,
span,
- format!(
- "the feature `{feature}` has been partially stabilized since {since} and is succeeded \
- by the feature `{implies}`"
- ),
- |lint| {
- lint.span_suggestion(
- span,
- &format!(
- "if you are using features which are still unstable, change to using `{implies}`"
- ),
- implies,
- Applicability::MaybeIncorrect,
- )
- .span_suggestion(
- tcx.sess.source_map().span_extend_to_line(span),
- "if you are using features which are now stable, remove this line",
- "",
- Applicability::MaybeIncorrect,
- )
+ errors::UnnecessaryPartialStableFeature {
+ span,
+ line: tcx.sess.source_map().span_extend_to_line(span),
+ feature,
+ since,
+ implies,
},
);
}
@@ -1131,7 +1112,10 @@ fn unnecessary_stable_feature_lint(
if since.as_str() == VERSION_PLACEHOLDER {
since = rust_version_symbol();
}
- tcx.struct_span_lint_hir(lint::builtin::STABLE_FEATURES, hir::CRATE_HIR_ID, span, format!("the feature `{feature}` has been stable since {since} and no longer requires an attribute to enable"), |lint| {
- lint
- });
+ tcx.emit_spanned_lint(
+ lint::builtin::STABLE_FEATURES,
+ hir::CRATE_HIR_ID,
+ span,
+ errors::UnnecessaryStableFeature { feature, since },
+ );
}
diff --git a/compiler/rustc_passes/src/upvars.rs b/compiler/rustc_passes/src/upvars.rs
index 605cf0a93..d87df706c 100644
--- a/compiler/rustc_passes/src/upvars.rs
+++ b/compiler/rustc_passes/src/upvars.rs
@@ -5,7 +5,7 @@ use rustc_hir as hir;
use rustc_hir::def::Res;
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{self, HirId};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::TyCtxt;
use rustc_span::Span;
diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml
index fa27bfc61..c930b3365 100644
--- a/compiler/rustc_plugin_impl/Cargo.toml
+++ b/compiler/rustc_plugin_impl/Cargo.toml
@@ -12,6 +12,7 @@ rustc_errors = { path = "../rustc_errors" }
rustc_lint = { path = "../rustc_lint" }
rustc_macros = { path = "../rustc_macros" }
rustc_metadata = { path = "../rustc_metadata" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_ast = { path = "../rustc_ast" }
rustc_session = { path = "../rustc_session" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_plugin_impl/src/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs
index 672189e22..faa7495ef 100644
--- a/compiler/rustc_plugin_impl/src/lib.rs
+++ b/compiler/rustc_plugin_impl/src/lib.rs
@@ -12,8 +12,8 @@
#![deny(rustc::diagnostic_outside_of_impl)]
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_lint::LintStore;
-use rustc_macros::fluent_messages;
mod errors;
pub mod load;
diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml
index 744cb77dd..08c406770 100644
--- a/compiler/rustc_privacy/Cargo.toml
+++ b/compiler/rustc_privacy/Cargo.toml
@@ -9,6 +9,7 @@ rustc_attr = { path = "../rustc_attr" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_macros = { path = "../rustc_macros" }
rustc_middle = { path = "../rustc_middle" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_privacy/messages.ftl b/compiler/rustc_privacy/messages.ftl
index a26d1b2b3..b68e8a78a 100644
--- a/compiler/rustc_privacy/messages.ftl
+++ b/compiler/rustc_privacy/messages.ftl
@@ -2,22 +2,22 @@ privacy_field_is_private = field `{$field_name}` of {$variant_descr} `{$def_path
privacy_field_is_private_is_update_syntax_label = field `{$field_name}` is private
privacy_field_is_private_label = private field
-privacy_item_is_private = {$kind} `{$descr}` is private
- .label = private {$kind}
-privacy_unnamed_item_is_private = {$kind} is private
- .label = private {$kind}
+privacy_from_private_dep_in_public_interface =
+ {$kind} `{$descr}` from private dependency '{$krate}' in public interface
privacy_in_public_interface = {$vis_descr} {$kind} `{$descr}` in public interface
.label = can't leak {$vis_descr} {$kind}
.visibility_label = `{$descr}` declared as {$vis_descr}
-privacy_report_effective_visibility = {$descr}
-
-privacy_from_private_dep_in_public_interface =
- {$kind} `{$descr}` from private dependency '{$krate}' in public interface
-
+privacy_item_is_private = {$kind} `{$descr}` is private
+ .label = private {$kind}
privacy_private_in_public_lint =
{$vis_descr} {$kind} `{$descr}` in public interface (error {$kind ->
[trait] E0445
*[other] E0446
})
+
+privacy_report_effective_visibility = {$descr}
+
+privacy_unnamed_item_is_private = {$kind} is private
+ .label = private {$kind}
diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs
index dcebfca08..65dfdf31e 100644
--- a/compiler/rustc_privacy/src/lib.rs
+++ b/compiler/rustc_privacy/src/lib.rs
@@ -17,17 +17,17 @@ use rustc_attr as attr;
use rustc_data_structures::fx::FxHashSet;
use rustc_data_structures::intern::Interned;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir as hir;
use rustc_hir::def::{DefKind, Res};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID};
use rustc_hir::intravisit::{self, Visitor};
use rustc_hir::{AssocItemKind, HirIdSet, ItemId, Node, PatKind};
-use rustc_macros::fluent_messages;
use rustc_middle::bug;
use rustc_middle::hir::nested_filter;
-use rustc_middle::middle::privacy::{EffectiveVisibilities, Level};
+use rustc_middle::middle::privacy::{EffectiveVisibilities, EffectiveVisibility, Level};
+use rustc_middle::query::Providers;
use rustc_middle::span_bug;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::subst::InternalSubsts;
use rustc_middle::ty::{self, Const, GenericParamDefKind};
use rustc_middle::ty::{TraitRef, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor};
@@ -38,7 +38,7 @@ use rustc_span::Span;
use std::marker::PhantomData;
use std::ops::ControlFlow;
-use std::{cmp, fmt, mem};
+use std::{fmt, mem};
use errors::{
FieldIsPrivate, FieldIsPrivateLabel, FromPrivateDependencyInPublicInterface, InPublicInterface,
@@ -127,18 +127,19 @@ where
fn visit_projection_ty(&mut self, projection: ty::AliasTy<'tcx>) -> ControlFlow<V::BreakTy> {
let tcx = self.def_id_visitor.tcx();
- let (trait_ref, assoc_substs) =
- if tcx.def_kind(projection.def_id) != DefKind::ImplTraitPlaceholder {
- projection.trait_ref_and_own_substs(tcx)
- } else {
- // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
- let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id);
- let trait_generics = tcx.generics_of(def_id);
- (
- tcx.mk_trait_ref(def_id, projection.substs.truncate_to(tcx, trait_generics)),
- &projection.substs[trait_generics.count()..],
- )
- };
+ let (trait_ref, assoc_substs) = if tcx.def_kind(projection.def_id)
+ != DefKind::ImplTraitPlaceholder
+ {
+ projection.trait_ref_and_own_substs(tcx)
+ } else {
+ // HACK(RPITIT): Remove this when RPITITs are lowered to regular assoc tys
+ let def_id = tcx.impl_trait_in_trait_parent_fn(projection.def_id);
+ let trait_generics = tcx.generics_of(def_id);
+ (
+ ty::TraitRef::new(tcx, def_id, projection.substs.truncate_to(tcx, trait_generics)),
+ &projection.substs[trait_generics.count()..],
+ )
+ };
self.visit_trait(trait_ref)?;
if self.def_id_visitor.shallow() {
ControlFlow::Continue(())
@@ -242,6 +243,39 @@ where
// This will also visit substs if necessary, so we don't need to recurse.
return self.visit_projection_ty(proj);
}
+ ty::Alias(ty::Inherent, data) => {
+ if self.def_id_visitor.skip_assoc_tys() {
+ // Visitors searching for minimal visibility/reachability want to
+ // conservatively approximate associated types like `Type::Alias`
+ // as visible/reachable even if `Type` is private.
+ // Ideally, associated types should be substituted in the same way as
+ // free type aliases, but this isn't done yet.
+ return ControlFlow::Continue(());
+ }
+
+ self.def_id_visitor.visit_def_id(
+ data.def_id,
+ "associated type",
+ &LazyDefPathStr { def_id: data.def_id, tcx },
+ )?;
+
+ struct LazyDefPathStr<'tcx> {
+ def_id: DefId,
+ tcx: TyCtxt<'tcx>,
+ }
+ impl<'tcx> fmt::Display for LazyDefPathStr<'tcx> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ write!(f, "{}", self.tcx.def_path_str(self.def_id))
+ }
+ }
+
+ // This will also visit substs if necessary, so we don't need to recurse.
+ return if self.def_id_visitor.shallow() {
+ ControlFlow::Continue(())
+ } else {
+ data.substs.iter().try_for_each(|subst| subst.visit_with(self))
+ };
+ }
ty::Dynamic(predicates, ..) => {
// All traits in the list are considered the "primary" part of the type
// and are visited by shallow visitors.
@@ -269,7 +303,7 @@ where
// and are visited by shallow visitors.
self.visit_predicates(ty::GenericPredicates {
parent: None,
- predicates: tcx.explicit_item_bounds(def_id),
+ predicates: tcx.explicit_item_bounds(def_id).skip_binder(),
})?;
}
}
@@ -374,8 +408,9 @@ impl VisibilityLike for ty::Visibility {
min(find.tcx.local_visibility(def_id), find.min, find.tcx)
}
}
-impl VisibilityLike for Option<Level> {
- const MAX: Self = Some(Level::Direct);
+
+impl VisibilityLike for Option<EffectiveVisibility> {
+ const MAX: Self = Some(EffectiveVisibility::from_vis(ty::Visibility::Public));
// Type inference is very smart sometimes.
// It can make an impl reachable even some components of its type or trait are unreachable.
// E.g. methods of `impl ReachableTrait<UnreachableTy> for ReachableTy<UnreachableTy> { ... }`
@@ -387,7 +422,13 @@ impl VisibilityLike for Option<Level> {
// (which require reaching the `DefId`s in them).
const SHALLOW: bool = true;
fn new_min(find: &FindMin<'_, '_, Self>, def_id: LocalDefId) -> Self {
- cmp::min(find.effective_visibilities.public_at_level(def_id), find.min)
+ if let Some(min) = find.min {
+ return find
+ .effective_visibilities
+ .effective_vis(def_id)
+ .map(|eff_vis| min.min(*eff_vis, find.tcx));
+ }
+ None
}
}
@@ -413,57 +454,90 @@ struct EmbargoVisitor<'tcx> {
/// n::p::f()
/// }
macro_reachable: FxHashSet<(LocalDefId, LocalDefId)>,
- /// Previous visibility level; `None` means unreachable.
- prev_level: Option<Level>,
+ /// Preliminary pass for marking all underlying types of `impl Trait`s as reachable.
+ impl_trait_pass: bool,
/// Has something changed in the level map?
changed: bool,
}
struct ReachEverythingInTheInterfaceVisitor<'a, 'tcx> {
- level: Option<Level>,
+ effective_vis: EffectiveVisibility,
item_def_id: LocalDefId,
ev: &'a mut EmbargoVisitor<'tcx>,
+ level: Level,
}
impl<'tcx> EmbargoVisitor<'tcx> {
- fn get(&self, def_id: LocalDefId) -> Option<Level> {
- self.effective_visibilities.public_at_level(def_id)
+ fn get(&self, def_id: LocalDefId) -> Option<EffectiveVisibility> {
+ self.effective_visibilities.effective_vis(def_id).copied()
+ }
+
+ // Updates node effective visibility.
+ fn update(
+ &mut self,
+ def_id: LocalDefId,
+ inherited_effective_vis: EffectiveVisibility,
+ level: Level,
+ ) {
+ let nominal_vis = self.tcx.local_visibility(def_id);
+ self.update_eff_vis(def_id, inherited_effective_vis, Some(nominal_vis), level);
}
- /// Updates node level and returns the updated level.
- fn update(&mut self, def_id: LocalDefId, level: Option<Level>) -> Option<Level> {
- let old_level = self.get(def_id);
- // Visibility levels can only grow.
- if level > old_level {
- self.effective_visibilities.set_public_at_level(
+ fn update_eff_vis(
+ &mut self,
+ def_id: LocalDefId,
+ inherited_effective_vis: EffectiveVisibility,
+ nominal_vis: Option<ty::Visibility>,
+ level: Level,
+ ) {
+ let private_vis = ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id));
+ if Some(private_vis) != nominal_vis {
+ self.changed |= self.effective_visibilities.update(
def_id,
- || ty::Visibility::Restricted(self.tcx.parent_module_from_def_id(def_id)),
- level.unwrap(),
+ nominal_vis,
+ || private_vis,
+ inherited_effective_vis,
+ level,
+ self.tcx,
);
- self.changed = true;
- level
- } else {
- old_level
}
}
fn reach(
&mut self,
def_id: LocalDefId,
- level: Option<Level>,
+ effective_vis: EffectiveVisibility,
+ ) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
+ ReachEverythingInTheInterfaceVisitor {
+ effective_vis,
+ item_def_id: def_id,
+ ev: self,
+ level: Level::Reachable,
+ }
+ }
+
+ fn reach_through_impl_trait(
+ &mut self,
+ def_id: LocalDefId,
+ effective_vis: EffectiveVisibility,
) -> ReachEverythingInTheInterfaceVisitor<'_, 'tcx> {
ReachEverythingInTheInterfaceVisitor {
- level: cmp::min(level, Some(Level::Reachable)),
+ effective_vis,
item_def_id: def_id,
ev: self,
+ level: Level::ReachableThroughImplTrait,
}
}
// We have to make sure that the items that macros might reference
// are reachable, since they might be exported transitively.
- fn update_reachability_from_macro(&mut self, local_def_id: LocalDefId, md: &MacroDef) {
+ fn update_reachability_from_macro(
+ &mut self,
+ local_def_id: LocalDefId,
+ md: &MacroDef,
+ macro_ev: EffectiveVisibility,
+ ) {
// Non-opaque macros cannot make other items more accessible than they already are.
-
let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id);
let attrs = self.tcx.hir().attrs(hir_id);
if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque {
@@ -476,7 +550,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
return;
}
- if self.get(local_def_id).is_none() {
+ if self.effective_visibilities.public_at_level(local_def_id).is_none() {
return;
}
@@ -485,7 +559,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
let mut module_def_id = macro_module_def_id;
loop {
let changed_reachability =
- self.update_macro_reachable(module_def_id, macro_module_def_id);
+ self.update_macro_reachable(module_def_id, macro_module_def_id, macro_ev);
if changed_reachability || module_def_id == CRATE_DEF_ID {
break;
}
@@ -499,28 +573,42 @@ impl<'tcx> EmbargoVisitor<'tcx> {
&mut self,
module_def_id: LocalDefId,
defining_mod: LocalDefId,
+ macro_ev: EffectiveVisibility,
) -> bool {
if self.macro_reachable.insert((module_def_id, defining_mod)) {
- self.update_macro_reachable_mod(module_def_id, defining_mod);
+ self.update_macro_reachable_mod(module_def_id, defining_mod, macro_ev);
true
} else {
false
}
}
- fn update_macro_reachable_mod(&mut self, module_def_id: LocalDefId, defining_mod: LocalDefId) {
+ fn update_macro_reachable_mod(
+ &mut self,
+ module_def_id: LocalDefId,
+ defining_mod: LocalDefId,
+ macro_ev: EffectiveVisibility,
+ ) {
let module = self.tcx.hir().get_module(module_def_id).0;
for item_id in module.item_ids {
let def_kind = self.tcx.def_kind(item_id.owner_id);
let vis = self.tcx.local_visibility(item_id.owner_id.def_id);
- self.update_macro_reachable_def(item_id.owner_id.def_id, def_kind, vis, defining_mod);
+ self.update_macro_reachable_def(
+ item_id.owner_id.def_id,
+ def_kind,
+ vis,
+ defining_mod,
+ macro_ev,
+ );
}
- for export in self.tcx.module_children_reexports(module_def_id) {
- if export.vis.is_accessible_from(defining_mod, self.tcx)
- && let Res::Def(def_kind, def_id) = export.res
+ for child in self.tcx.module_children_local(module_def_id) {
+ // FIXME: Use module children for the logic above too.
+ if !child.reexport_chain.is_empty()
+ && child.vis.is_accessible_from(defining_mod, self.tcx)
+ && let Res::Def(def_kind, def_id) = child.res
&& let Some(def_id) = def_id.as_local() {
let vis = self.tcx.local_visibility(def_id);
- self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod);
+ self.update_macro_reachable_def(def_id, def_kind, vis, defining_mod, macro_ev);
}
}
}
@@ -531,16 +619,14 @@ impl<'tcx> EmbargoVisitor<'tcx> {
def_kind: DefKind,
vis: ty::Visibility,
module: LocalDefId,
+ macro_ev: EffectiveVisibility,
) {
- let level = Some(Level::Reachable);
- if vis.is_public() {
- self.update(def_id, level);
- }
+ self.update(def_id, macro_ev, Level::Reachable);
match def_kind {
// No type privacy, so can be directly marked as reachable.
DefKind::Const | DefKind::Static(_) | DefKind::TraitAlias | DefKind::TyAlias => {
if vis.is_accessible_from(module, self.tcx) {
- self.update(def_id, level);
+ self.update(def_id, macro_ev, Level::Reachable);
}
}
@@ -552,7 +638,7 @@ impl<'tcx> EmbargoVisitor<'tcx> {
let item = self.tcx.hir().expect_item(def_id);
if let hir::ItemKind::Macro(MacroDef { macro_rules: false, .. }, _) = item.kind {
if vis.is_accessible_from(module, self.tcx) {
- self.update(def_id, level);
+ self.update(def_id, macro_ev, Level::Reachable);
}
}
}
@@ -563,26 +649,24 @@ impl<'tcx> EmbargoVisitor<'tcx> {
// the module, however may be reachable.
DefKind::Mod => {
if vis.is_accessible_from(module, self.tcx) {
- self.update_macro_reachable(def_id, module);
+ self.update_macro_reachable(def_id, module, macro_ev);
}
}
DefKind::Struct | DefKind::Union => {
// While structs and unions have type privacy, their fields do not.
- if vis.is_public() {
- let item = self.tcx.hir().expect_item(def_id);
- if let hir::ItemKind::Struct(ref struct_def, _)
- | hir::ItemKind::Union(ref struct_def, _) = item.kind
- {
- for field in struct_def.fields() {
- let field_vis = self.tcx.local_visibility(field.def_id);
- if field_vis.is_accessible_from(module, self.tcx) {
- self.reach(field.def_id, level).ty();
- }
+ let item = self.tcx.hir().expect_item(def_id);
+ if let hir::ItemKind::Struct(ref struct_def, _)
+ | hir::ItemKind::Union(ref struct_def, _) = item.kind
+ {
+ for field in struct_def.fields() {
+ let field_vis = self.tcx.local_visibility(field.def_id);
+ if field_vis.is_accessible_from(module, self.tcx) {
+ self.reach(field.def_id, macro_ev).ty();
}
- } else {
- bug!("item {:?} with DefKind {:?}", item, def_kind);
}
+ } else {
+ bug!("item {:?} with DefKind {:?}", item, def_kind);
}
}
@@ -617,127 +701,53 @@ impl<'tcx> EmbargoVisitor<'tcx> {
}
impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
- type NestedFilter = nested_filter::All;
-
- /// We want to visit items in the context of their containing
- /// module and so forth, so supply a crate for doing a deep walk.
- fn nested_visit_map(&mut self) -> Self::Map {
- self.tcx.hir()
- }
-
fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) {
- let item_level = match item.kind {
- hir::ItemKind::Impl { .. } => {
- let impl_level = Option::<Level>::of_impl(
- item.owner_id.def_id,
- self.tcx,
- &self.effective_visibilities,
- );
- self.update(item.owner_id.def_id, impl_level)
- }
- _ => self.get(item.owner_id.def_id),
- };
-
- // Update levels of nested things.
- match item.kind {
- hir::ItemKind::Enum(ref def, _) => {
- for variant in def.variants {
- let variant_level = self.update(variant.def_id, item_level);
- if let Some(ctor_def_id) = variant.data.ctor_def_id() {
- self.update(ctor_def_id, item_level);
- }
- for field in variant.data.fields() {
- self.update(field.def_id, variant_level);
- }
- }
- }
- hir::ItemKind::Impl(ref impl_) => {
- for impl_item_ref in impl_.items {
- if impl_.of_trait.is_some()
- || self.tcx.visibility(impl_item_ref.id.owner_id).is_public()
- {
- self.update(impl_item_ref.id.owner_id.def_id, item_level);
- }
- }
- }
- hir::ItemKind::Trait(.., trait_item_refs) => {
- for trait_item_ref in trait_item_refs {
- self.update(trait_item_ref.id.owner_id.def_id, item_level);
- }
- }
- hir::ItemKind::Struct(ref def, _) | hir::ItemKind::Union(ref def, _) => {
- if let Some(ctor_def_id) = def.ctor_def_id() {
- self.update(ctor_def_id, item_level);
- }
- for field in def.fields() {
- let vis = self.tcx.visibility(field.def_id);
- if vis.is_public() {
- self.update(field.def_id, item_level);
- }
- }
- }
- hir::ItemKind::Macro(ref macro_def, _) => {
- self.update_reachability_from_macro(item.owner_id.def_id, macro_def);
- }
- hir::ItemKind::ForeignMod { items, .. } => {
- for foreign_item in items {
- if self.tcx.visibility(foreign_item.id.owner_id).is_public() {
- self.update(foreign_item.id.owner_id.def_id, item_level);
- }
- }
- }
-
- hir::ItemKind::OpaqueTy(..)
- | hir::ItemKind::Use(..)
- | hir::ItemKind::Static(..)
- | hir::ItemKind::Const(..)
- | hir::ItemKind::GlobalAsm(..)
- | hir::ItemKind::TyAlias(..)
- | hir::ItemKind::Mod(..)
- | hir::ItemKind::TraitAlias(..)
- | hir::ItemKind::Fn(..)
- | hir::ItemKind::ExternCrate(..) => {}
+ if self.impl_trait_pass
+ && let hir::ItemKind::OpaqueTy(ref opaque) = item.kind
+ && !opaque.in_trait {
+ // FIXME: This is some serious pessimization intended to workaround deficiencies
+ // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
+ // reachable if they are returned via `impl Trait`, even from private functions.
+ let pub_ev = EffectiveVisibility::from_vis(ty::Visibility::Public);
+ self.reach_through_impl_trait(item.owner_id.def_id, pub_ev)
+ .generics()
+ .predicates()
+ .ty();
+ return;
}
- // Mark all items in interfaces of reachable items as reachable.
+ // Update levels of nested things and mark all items
+ // in interfaces of reachable items as reachable.
+ let item_ev = self.get(item.owner_id.def_id);
match item.kind {
- // The interface is empty.
- hir::ItemKind::Macro(..) | hir::ItemKind::ExternCrate(..) => {}
- // All nested items are checked by `visit_item`.
- hir::ItemKind::Mod(..) => {}
- // Handled in `rustc_resolve`.
- hir::ItemKind::Use(..) => {}
- // The interface is empty.
- hir::ItemKind::GlobalAsm(..) => {}
- hir::ItemKind::OpaqueTy(ref opaque) => {
- // HACK(jynelson): trying to infer the type of `impl trait` breaks `async-std` (and `pub async fn` in general)
- // Since rustdoc never needs to do codegen and doesn't care about link-time reachability,
- // mark this as unreachable.
- // See https://github.com/rust-lang/rust/issues/75100
- if !opaque.in_trait && !self.tcx.sess.opts.actually_rustdoc {
- // FIXME: This is some serious pessimization intended to workaround deficiencies
- // in the reachability pass (`middle/reachable.rs`). Types are marked as link-time
- // reachable if they are returned via `impl Trait`, even from private functions.
- let exist_level = cmp::max(item_level, Some(Level::ReachableThroughImplTrait));
- self.reach(item.owner_id.def_id, exist_level).generics().predicates().ty();
+ // The interface is empty, and no nested items.
+ hir::ItemKind::Use(..)
+ | hir::ItemKind::ExternCrate(..)
+ | hir::ItemKind::GlobalAsm(..) => {}
+ // The interface is empty, and all nested items are processed by `visit_item`.
+ hir::ItemKind::Mod(..) | hir::ItemKind::OpaqueTy(..) => {}
+ hir::ItemKind::Macro(ref macro_def, _) => {
+ if let Some(item_ev) = item_ev {
+ self.update_reachability_from_macro(item.owner_id.def_id, macro_def, item_ev);
}
}
- // Visit everything.
hir::ItemKind::Const(..)
| hir::ItemKind::Static(..)
| hir::ItemKind::Fn(..)
| hir::ItemKind::TyAlias(..) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level).generics().predicates().ty();
+ if let Some(item_ev) = item_ev {
+ self.reach(item.owner_id.def_id, item_ev).generics().predicates().ty();
}
}
hir::ItemKind::Trait(.., trait_item_refs) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level).generics().predicates();
+ if let Some(item_ev) = item_ev {
+ self.reach(item.owner_id.def_id, item_ev).generics().predicates();
for trait_item_ref in trait_item_refs {
+ self.update(trait_item_ref.id.owner_id.def_id, item_ev, Level::Reachable);
+
let tcx = self.tcx;
- let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_level);
+ let mut reach = self.reach(trait_item_ref.id.owner_id.def_id, item_ev);
reach.generics().predicates();
if trait_item_ref.kind == AssocItemKind::Type
@@ -751,98 +761,94 @@ impl<'tcx> Visitor<'tcx> for EmbargoVisitor<'tcx> {
}
}
hir::ItemKind::TraitAlias(..) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level).generics().predicates();
+ if let Some(item_ev) = item_ev {
+ self.reach(item.owner_id.def_id, item_ev).generics().predicates();
}
}
- // Visit everything except for private impl items.
hir::ItemKind::Impl(ref impl_) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level)
+ if let Some(item_ev) = Option::<EffectiveVisibility>::of_impl(
+ item.owner_id.def_id,
+ self.tcx,
+ &self.effective_visibilities,
+ ) {
+ self.update_eff_vis(item.owner_id.def_id, item_ev, None, Level::Direct);
+
+ self.reach(item.owner_id.def_id, item_ev)
.generics()
.predicates()
.ty()
.trait_ref();
for impl_item_ref in impl_.items {
- let impl_item_level = self.get(impl_item_ref.id.owner_id.def_id);
- if impl_item_level.is_some() {
- self.reach(impl_item_ref.id.owner_id.def_id, impl_item_level)
- .generics()
- .predicates()
- .ty();
+ let def_id = impl_item_ref.id.owner_id.def_id;
+ let nominal_vis =
+ impl_.of_trait.is_none().then(|| self.tcx.local_visibility(def_id));
+ self.update_eff_vis(def_id, item_ev, nominal_vis, Level::Direct);
+
+ if let Some(impl_item_ev) = self.get(def_id) {
+ self.reach(def_id, impl_item_ev).generics().predicates().ty();
}
}
}
}
-
- // Visit everything, but enum variants have their own levels.
hir::ItemKind::Enum(ref def, _) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level).generics().predicates();
+ if let Some(item_ev) = item_ev {
+ self.reach(item.owner_id.def_id, item_ev).generics().predicates();
}
for variant in def.variants {
- let variant_level = self.get(variant.def_id);
- if variant_level.is_some() {
+ if let Some(item_ev) = item_ev {
+ self.update(variant.def_id, item_ev, Level::Reachable);
+ }
+
+ if let Some(variant_ev) = self.get(variant.def_id) {
+ if let Some(ctor_def_id) = variant.data.ctor_def_id() {
+ self.update(ctor_def_id, variant_ev, Level::Reachable);
+ }
for field in variant.data.fields() {
- self.reach(field.def_id, variant_level).ty();
+ self.update(field.def_id, variant_ev, Level::Reachable);
+ self.reach(field.def_id, variant_ev).ty();
}
// Corner case: if the variant is reachable, but its
// enum is not, make the enum reachable as well.
- self.reach(item.owner_id.def_id, variant_level).ty();
+ self.reach(item.owner_id.def_id, variant_ev).ty();
}
if let Some(ctor_def_id) = variant.data.ctor_def_id() {
- let ctor_level = self.get(ctor_def_id);
- if ctor_level.is_some() {
- self.reach(item.owner_id.def_id, ctor_level).ty();
+ if let Some(ctor_ev) = self.get(ctor_def_id) {
+ self.reach(item.owner_id.def_id, ctor_ev).ty();
}
}
}
}
- // Visit everything, but foreign items have their own levels.
hir::ItemKind::ForeignMod { items, .. } => {
for foreign_item in items {
- let foreign_item_level = self.get(foreign_item.id.owner_id.def_id);
- if foreign_item_level.is_some() {
- self.reach(foreign_item.id.owner_id.def_id, foreign_item_level)
+ if let Some(foreign_item_ev) = self.get(foreign_item.id.owner_id.def_id) {
+ self.reach(foreign_item.id.owner_id.def_id, foreign_item_ev)
.generics()
.predicates()
.ty();
}
}
}
- // Visit everything except for private fields.
hir::ItemKind::Struct(ref struct_def, _) | hir::ItemKind::Union(ref struct_def, _) => {
- if item_level.is_some() {
- self.reach(item.owner_id.def_id, item_level).generics().predicates();
+ if let Some(item_ev) = item_ev {
+ self.reach(item.owner_id.def_id, item_ev).generics().predicates();
for field in struct_def.fields() {
- let field_level = self.get(field.def_id);
- if field_level.is_some() {
- self.reach(field.def_id, field_level).ty();
+ self.update(field.def_id, item_ev, Level::Reachable);
+ if let Some(field_ev) = self.get(field.def_id) {
+ self.reach(field.def_id, field_ev).ty();
}
}
}
if let Some(ctor_def_id) = struct_def.ctor_def_id() {
- let ctor_level = self.get(ctor_def_id);
- if ctor_level.is_some() {
- self.reach(item.owner_id.def_id, ctor_level).ty();
+ if let Some(item_ev) = item_ev {
+ self.update(ctor_def_id, item_ev, Level::Reachable);
+ }
+ if let Some(ctor_ev) = self.get(ctor_def_id) {
+ self.reach(item.owner_id.def_id, ctor_ev).ty();
}
}
}
}
-
- let orig_level = mem::replace(&mut self.prev_level, item_level);
- intravisit::walk_item(self, item);
- self.prev_level = orig_level;
- }
-
- fn visit_block(&mut self, b: &'tcx hir::Block<'tcx>) {
- // Blocks can have public items, for example impls, but they always
- // start as completely private regardless of publicity of a function,
- // constant, type, field, etc., in which this block resides.
- let orig_level = mem::replace(&mut self.prev_level, None);
- intravisit::walk_block(self, b);
- self.prev_level = orig_level;
}
}
@@ -896,11 +902,7 @@ impl<'tcx> DefIdVisitor<'tcx> for ReachEverythingInTheInterfaceVisitor<'_, 'tcx>
_descr: &dyn fmt::Display,
) -> ControlFlow<Self::BreakTy> {
if let Some(def_id) = def_id.as_local() {
- if let (ty::Visibility::Public, _) | (_, Some(Level::ReachableThroughImplTrait)) =
- (self.tcx().visibility(def_id.to_def_id()), self.level)
- {
- self.ev.update(def_id, self.level);
- }
+ self.ev.update_eff_vis(def_id, self.effective_vis, None, self.level);
}
ControlFlow::Continue(())
}
@@ -1784,7 +1786,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> {
fn bounds(&mut self) -> &mut Self {
self.visit_predicates(ty::GenericPredicates {
parent: None,
- predicates: self.tcx.explicit_item_bounds(self.item_def_id),
+ predicates: self.tcx.explicit_item_bounds(self.item_def_id).skip_binder(),
});
self
}
@@ -2128,13 +2130,24 @@ fn effective_visibilities(tcx: TyCtxt<'_>, (): ()) -> &EffectiveVisibilities {
tcx,
effective_visibilities: tcx.resolutions(()).effective_visibilities.clone(),
macro_reachable: Default::default(),
- prev_level: Some(Level::Direct),
+ // HACK(jynelson): trying to infer the type of `impl Trait` breaks `async-std` (and
+ // `pub async fn` in general). Since rustdoc never needs to do codegen and doesn't
+ // care about link-time reachability, keep them unreachable (issue #75100).
+ impl_trait_pass: !tcx.sess.opts.actually_rustdoc,
changed: false,
};
visitor.effective_visibilities.check_invariants(tcx, true);
+ if visitor.impl_trait_pass {
+ // Underlying types of `impl Trait`s are marked as reachable unconditionally,
+ // so this pass doesn't need to be a part of the fixed point iteration below.
+ tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
+ visitor.impl_trait_pass = false;
+ visitor.changed = false;
+ }
+
loop {
- tcx.hir().walk_toplevel_module(&mut visitor);
+ tcx.hir().visit_all_item_likes_in_crate(&mut visitor);
if visitor.changed {
visitor.changed = false;
} else {
diff --git a/compiler/rustc_query_impl/Cargo.toml b/compiler/rustc_query_impl/Cargo.toml
index b107a3f03..e59699346 100644
--- a/compiler/rustc_query_impl/Cargo.toml
+++ b/compiler/rustc_query_impl/Cargo.toml
@@ -7,6 +7,8 @@ edition = "2021"
[dependencies]
+memoffset = { version = "0.6.0", features = ["unstable_const"] }
+field-offset = "0.3.5"
measureme = "10.0.0"
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
diff --git a/compiler/rustc_query_impl/src/lib.rs b/compiler/rustc_query_impl/src/lib.rs
index 7001a1eed..4cf0f1305 100644
--- a/compiler/rustc_query_impl/src/lib.rs
+++ b/compiler/rustc_query_impl/src/lib.rs
@@ -3,60 +3,225 @@
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
// this shouldn't be necessary, but the check for `&mut _` is too naive and denies returning a function pointer that takes a mut ref
#![feature(const_mut_refs)]
+#![feature(const_refs_to_cell)]
#![feature(min_specialization)]
#![feature(never_type)]
#![feature(rustc_attrs)]
#![recursion_limit = "256"]
-#![allow(rustc::potential_query_instability)]
+#![allow(rustc::potential_query_instability, unused_parens)]
#![deny(rustc::untranslatable_diagnostic)]
#![deny(rustc::diagnostic_outside_of_impl)]
#[macro_use]
-extern crate rustc_macros;
-#[macro_use]
extern crate rustc_middle;
+use crate::plumbing::{__rust_begin_short_backtrace, encode_all_query_results, try_mark_green};
+use field_offset::offset_of;
+use rustc_data_structures::stable_hasher::HashStable;
use rustc_data_structures::sync::AtomicU64;
use rustc_middle::arena::Arena;
+use rustc_middle::dep_graph::DepNodeIndex;
use rustc_middle::dep_graph::{self, DepKind, DepKindStruct};
use rustc_middle::query::erase::{erase, restore, Erase};
+use rustc_middle::query::on_disk_cache::{CacheEncoder, EncodedDepNodeIndex, OnDiskCache};
+use rustc_middle::query::plumbing::{
+ DynamicQuery, QueryKeyStringCache, QuerySystem, QuerySystemFns,
+};
use rustc_middle::query::AsLocalKey;
-use rustc_middle::ty::query::{
- query_keys, query_provided, query_provided_to_value, query_storage, query_values,
+use rustc_middle::query::{
+ queries, DynamicQueries, ExternProviders, Providers, QueryCaches, QueryEngine, QueryStates,
};
-use rustc_middle::ty::query::{ExternProviders, Providers, QueryEngine};
use rustc_middle::ty::TyCtxt;
use rustc_query_system::dep_graph::SerializedDepNodeIndex;
+use rustc_query_system::ich::StableHashingContext;
+use rustc_query_system::query::{
+ get_query_incr, get_query_non_incr, HashResult, QueryCache, QueryConfig, QueryInfo, QueryMap,
+ QueryMode, QueryState,
+};
+use rustc_query_system::HandleCycleError;
use rustc_query_system::Value;
use rustc_span::Span;
#[macro_use]
mod plumbing;
-pub use plumbing::QueryCtxt;
-use rustc_query_system::query::*;
-#[cfg(parallel_compiler)]
-pub use rustc_query_system::query::{deadlock, QueryContext};
-
-pub use rustc_query_system::query::QueryConfig;
-
-mod on_disk_cache;
-pub use on_disk_cache::OnDiskCache;
+pub use crate::plumbing::QueryCtxt;
mod profiling_support;
pub use self::profiling_support::alloc_self_profile_query_strings;
-/// This is implemented per query and restoring query values from their erased state.
-trait QueryConfigRestored<'tcx>: QueryConfig<QueryCtxt<'tcx>> + Default {
- type RestoredValue;
+struct DynamicConfig<
+ 'tcx,
+ C: QueryCache,
+ const ANON: bool,
+ const DEPTH_LIMIT: bool,
+ const FEEDABLE: bool,
+> {
+ dynamic: &'tcx DynamicQuery<'tcx, C>,
+}
- fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue;
+impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Copy
+ for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
+{
+}
+impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool> Clone
+ for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
+{
+ fn clone(&self) -> Self {
+ DynamicConfig { dynamic: self.dynamic }
+ }
}
-rustc_query_append! { define_queries! }
+impl<'tcx, C: QueryCache, const ANON: bool, const DEPTH_LIMIT: bool, const FEEDABLE: bool>
+ QueryConfig<QueryCtxt<'tcx>> for DynamicConfig<'tcx, C, ANON, DEPTH_LIMIT, FEEDABLE>
+where
+ for<'a> C::Key: HashStable<StableHashingContext<'a>>,
+{
+ type Key = C::Key;
+ type Value = C::Value;
+ type Cache = C;
+
+ #[inline(always)]
+ fn name(self) -> &'static str {
+ self.dynamic.name
+ }
+
+ #[inline(always)]
+ fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
+ (self.dynamic.cache_on_disk)(tcx, key)
+ }
+
+ #[inline(always)]
+ fn query_state<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, DepKind>
+ where
+ QueryCtxt<'tcx>: 'a,
+ {
+ self.dynamic.query_state.apply(&qcx.tcx.query_system.states)
+ }
+
+ #[inline(always)]
+ fn query_cache<'a>(self, qcx: QueryCtxt<'tcx>) -> &'a Self::Cache
+ where
+ 'tcx: 'a,
+ {
+ self.dynamic.query_cache.apply(&qcx.tcx.query_system.caches)
+ }
+
+ #[inline(always)]
+ fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
+ (self.dynamic.execute_query)(tcx, key)
+ }
+
+ #[inline(always)]
+ fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
+ (self.dynamic.compute)(qcx.tcx, key)
+ }
+
+ #[inline(always)]
+ fn try_load_from_disk(
+ self,
+ qcx: QueryCtxt<'tcx>,
+ key: &Self::Key,
+ prev_index: SerializedDepNodeIndex,
+ index: DepNodeIndex,
+ ) -> Option<Self::Value> {
+ if self.dynamic.can_load_from_disk {
+ (self.dynamic.try_load_from_disk)(qcx.tcx, key, prev_index, index)
+ } else {
+ None
+ }
+ }
+
+ #[inline]
+ fn loadable_from_disk(
+ self,
+ qcx: QueryCtxt<'tcx>,
+ key: &Self::Key,
+ index: SerializedDepNodeIndex,
+ ) -> bool {
+ (self.dynamic.loadable_from_disk)(qcx.tcx, key, index)
+ }
-impl<'tcx> Queries<'tcx> {
- // Force codegen in the dyn-trait transformation in this crate.
- pub fn as_dyn(&'tcx self) -> &'tcx dyn QueryEngine<'tcx> {
- self
+ fn value_from_cycle_error(
+ self,
+ tcx: TyCtxt<'tcx>,
+ cycle: &[QueryInfo<DepKind>],
+ ) -> Self::Value {
+ (self.dynamic.value_from_cycle_error)(tcx, cycle)
+ }
+
+ #[inline(always)]
+ fn format_value(self) -> fn(&Self::Value) -> String {
+ self.dynamic.format_value
+ }
+
+ #[inline(always)]
+ fn anon(self) -> bool {
+ ANON
+ }
+
+ #[inline(always)]
+ fn eval_always(self) -> bool {
+ self.dynamic.eval_always
+ }
+
+ #[inline(always)]
+ fn depth_limit(self) -> bool {
+ DEPTH_LIMIT
+ }
+
+ #[inline(always)]
+ fn feedable(self) -> bool {
+ FEEDABLE
+ }
+
+ #[inline(always)]
+ fn dep_kind(self) -> DepKind {
+ self.dynamic.dep_kind
+ }
+
+ #[inline(always)]
+ fn handle_cycle_error(self) -> HandleCycleError {
+ self.dynamic.handle_cycle_error
+ }
+
+ #[inline(always)]
+ fn hash_result(self) -> HashResult<Self::Value> {
+ self.dynamic.hash_result
+ }
+}
+
+/// This is implemented per query. It allows restoring query values from their erased state
+/// and constructing a QueryConfig.
+trait QueryConfigRestored<'tcx> {
+ type RestoredValue;
+ type Config: QueryConfig<QueryCtxt<'tcx>>;
+
+ fn config(tcx: TyCtxt<'tcx>) -> Self::Config;
+ fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value)
+ -> Self::RestoredValue;
+}
+
+pub fn query_system<'tcx>(
+ local_providers: Providers,
+ extern_providers: ExternProviders,
+ on_disk_cache: Option<OnDiskCache<'tcx>>,
+ incremental: bool,
+) -> QuerySystem<'tcx> {
+ QuerySystem {
+ states: Default::default(),
+ arenas: Default::default(),
+ caches: Default::default(),
+ dynamic_queries: dynamic_queries(),
+ on_disk_cache,
+ fns: QuerySystemFns {
+ engine: engine(incremental),
+ local_providers,
+ extern_providers,
+ encode_query_results: encode_all_query_results,
+ try_mark_green: try_mark_green,
+ },
+ jobs: AtomicU64::new(1),
}
}
+
+rustc_query_append! { define_queries! }
diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs
index afbead7d1..244f0e84b 100644
--- a/compiler/rustc_query_impl/src/plumbing.rs
+++ b/compiler/rustc_query_impl/src/plumbing.rs
@@ -2,35 +2,45 @@
//! generate the actual methods on tcx which find and execute the provider,
//! manage the caches, and so forth.
-use crate::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
-use crate::profiling_support::QueryKeyStringCache;
-use crate::{on_disk_cache, Queries};
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
-use rustc_data_structures::sync::{AtomicU64, Lock};
-use rustc_errors::{Diagnostic, Handler};
+use crate::rustc_middle::dep_graph::DepContext;
+use crate::rustc_middle::ty::TyEncoder;
+use crate::QueryConfigRestored;
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
+use rustc_data_structures::sync::Lock;
+use rustc_errors::Diagnostic;
+use rustc_index::Idx;
use rustc_middle::dep_graph::{
self, DepKind, DepKindStruct, DepNode, DepNodeIndex, SerializedDepNodeIndex,
};
+use rustc_middle::query::on_disk_cache::AbsoluteBytePos;
+use rustc_middle::query::on_disk_cache::{CacheDecoder, CacheEncoder, EncodedDepNodeIndex};
use rustc_middle::query::Key;
use rustc_middle::ty::tls::{self, ImplicitCtxt};
use rustc_middle::ty::{self, TyCtxt};
use rustc_query_system::dep_graph::{DepNodeParams, HasDepContext};
use rustc_query_system::ich::StableHashingContext;
use rustc_query_system::query::{
- force_query, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects, QueryStackFrame,
+ force_query, QueryCache, QueryConfig, QueryContext, QueryJobId, QueryMap, QuerySideEffects,
+ QueryStackFrame,
};
use rustc_query_system::{LayoutOfDepth, QueryOverflow};
use rustc_serialize::Decodable;
+use rustc_serialize::Encodable;
use rustc_session::Limit;
use rustc_span::def_id::LOCAL_CRATE;
-use std::any::Any;
use std::num::NonZeroU64;
use thin_vec::ThinVec;
#[derive(Copy, Clone)]
pub struct QueryCtxt<'tcx> {
pub tcx: TyCtxt<'tcx>,
- pub queries: &'tcx Queries<'tcx>,
+}
+
+impl<'tcx> QueryCtxt<'tcx> {
+ #[inline]
+ pub fn new(tcx: TyCtxt<'tcx>) -> Self {
+ QueryCtxt { tcx }
+ }
}
impl<'tcx> std::ops::Deref for QueryCtxt<'tcx> {
@@ -53,44 +63,56 @@ impl<'tcx> HasDepContext for QueryCtxt<'tcx> {
}
impl QueryContext for QueryCtxt<'_> {
+ #[inline]
fn next_job_id(self) -> QueryJobId {
QueryJobId(
NonZeroU64::new(
- self.queries.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed),
+ self.query_system.jobs.fetch_add(1, rustc_data_structures::sync::Ordering::Relaxed),
)
.unwrap(),
)
}
+ #[inline]
fn current_query_job(self) -> Option<QueryJobId> {
- tls::with_related_context(*self, |icx| icx.query)
+ tls::with_related_context(self.tcx, |icx| icx.query)
}
fn try_collect_active_jobs(self) -> Option<QueryMap<DepKind>> {
- self.queries.try_collect_active_jobs(*self)
+ let mut jobs = QueryMap::default();
+
+ for collect in super::TRY_COLLECT_ACTIVE_JOBS.iter() {
+ collect(self.tcx, &mut jobs);
+ }
+
+ Some(jobs)
}
// Interactions with on_disk_cache
fn load_side_effects(self, prev_dep_node_index: SerializedDepNodeIndex) -> QuerySideEffects {
- self.queries
+ self.query_system
.on_disk_cache
.as_ref()
- .map(|c| c.load_side_effects(*self, prev_dep_node_index))
+ .map(|c| c.load_side_effects(self.tcx, prev_dep_node_index))
.unwrap_or_default()
}
+ #[inline(never)]
+ #[cold]
fn store_side_effects(self, dep_node_index: DepNodeIndex, side_effects: QuerySideEffects) {
- if let Some(c) = self.queries.on_disk_cache.as_ref() {
+ if let Some(c) = self.query_system.on_disk_cache.as_ref() {
c.store_side_effects(dep_node_index, side_effects)
}
}
+ #[inline(never)]
+ #[cold]
fn store_side_effects_for_anon_node(
self,
dep_node_index: DepNodeIndex,
side_effects: QuerySideEffects,
) {
- if let Some(c) = self.queries.on_disk_cache.as_ref() {
+ if let Some(c) = self.query_system.on_disk_cache.as_ref() {
c.store_side_effects_for_anon_node(dep_node_index, side_effects)
}
}
@@ -109,14 +131,14 @@ impl QueryContext for QueryCtxt<'_> {
// The `TyCtxt` stored in TLS has the same global interner lifetime
// as `self`, so we use `with_related_context` to relate the 'tcx lifetimes
// when accessing the `ImplicitCtxt`.
- tls::with_related_context(*self, move |current_icx| {
+ tls::with_related_context(self.tcx, move |current_icx| {
if depth_limit && !self.recursion_limit().value_within_limit(current_icx.query_depth) {
self.depth_limit_error(token);
}
// Update the `ImplicitCtxt` to point to our new query job.
let new_icx = ImplicitCtxt {
- tcx: *self,
+ tcx: self.tcx,
query: Some(token),
diagnostics,
query_depth: current_icx.query_depth + depth_limit as usize,
@@ -152,51 +174,18 @@ impl QueryContext for QueryCtxt<'_> {
}
}
-impl<'tcx> QueryCtxt<'tcx> {
- #[inline]
- pub fn from_tcx(tcx: TyCtxt<'tcx>) -> Self {
- let queries = tcx.queries.as_any();
- let queries = unsafe {
- let queries = std::mem::transmute::<&dyn Any, &dyn Any>(queries);
- let queries = queries.downcast_ref().unwrap();
- let queries = std::mem::transmute::<&Queries<'_>, &Queries<'_>>(queries);
- queries
- };
- QueryCtxt { tcx, queries }
- }
-
- pub(crate) fn on_disk_cache(self) -> Option<&'tcx on_disk_cache::OnDiskCache<'tcx>> {
- self.queries.on_disk_cache.as_ref()
- }
-
- pub(super) fn encode_query_results(
- self,
- encoder: &mut CacheEncoder<'_, 'tcx>,
- query_result_index: &mut EncodedDepNodeIndex,
- ) {
- for query in &self.queries.query_structs {
- if let Some(encode) = query.encode_query_results {
- encode(self, encoder, query_result_index);
- }
- }
- }
-
- pub fn try_print_query_stack(
- self,
- query: Option<QueryJobId>,
- handler: &Handler,
- num_frames: Option<usize>,
- ) -> usize {
- rustc_query_system::query::print_query_stack(self, query, handler, num_frames)
- }
+pub(super) fn try_mark_green<'tcx>(tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool {
+ tcx.dep_graph.try_mark_green(QueryCtxt::new(tcx), dep_node).is_some()
}
-#[derive(Clone, Copy)]
-pub(crate) struct QueryStruct<'tcx> {
- pub try_collect_active_jobs: fn(QueryCtxt<'tcx>, &mut QueryMap<DepKind>) -> Option<()>,
- pub alloc_self_profile_query_strings: fn(TyCtxt<'tcx>, &mut QueryKeyStringCache),
- pub encode_query_results:
- Option<fn(QueryCtxt<'tcx>, &mut CacheEncoder<'_, 'tcx>, &mut EncodedDepNodeIndex)>,
+pub(super) fn encode_all_query_results<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ encoder: &mut CacheEncoder<'_, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex,
+) {
+ for encode in super::ENCODE_QUERY_RESULTS.iter().copied().filter_map(|e| e) {
+ encode(tcx, encoder, query_result_index);
+ }
}
macro_rules! handle_cycle_error {
@@ -275,14 +264,14 @@ macro_rules! hash_result {
}
macro_rules! call_provider {
- ([][$qcx:expr, $name:ident, $key:expr]) => {{
- ($qcx.queries.local_providers.$name)($qcx.tcx, $key)
+ ([][$tcx:expr, $name:ident, $key:expr]) => {{
+ ($tcx.query_system.fns.local_providers.$name)($tcx, $key)
}};
- ([(separate_provide_extern) $($rest:tt)*][$qcx:expr, $name:ident, $key:expr]) => {{
+ ([(separate_provide_extern) $($rest:tt)*][$tcx:expr, $name:ident, $key:expr]) => {{
if let Some(key) = $key.as_local_key() {
- ($qcx.queries.local_providers.$name)($qcx.tcx, key)
+ ($tcx.query_system.fns.local_providers.$name)($tcx, key)
} else {
- ($qcx.queries.extern_providers.$name)($qcx.tcx, $key)
+ ($tcx.query_system.fns.extern_providers.$name)($tcx, $key)
}
}};
([$other:tt $($modifiers:tt)*][$($args:tt)*]) => {
@@ -306,7 +295,7 @@ pub(crate) fn create_query_frame<
'tcx,
K: Copy + Key + for<'a> HashStable<StableHashingContext<'a>>,
>(
- tcx: QueryCtxt<'tcx>,
+ tcx: TyCtxt<'tcx>,
do_describe: fn(TyCtxt<'tcx>, K) -> String,
key: K,
kind: DepKind,
@@ -318,7 +307,7 @@ pub(crate) fn create_query_frame<
// Showing visible path instead of any path is not that important in production.
ty::print::with_no_visible_paths!(
// Force filename-line mode to avoid invoking `type_of` query.
- ty::print::with_forced_impl_filename_line!(do_describe(tcx.tcx, key))
+ ty::print::with_forced_impl_filename_line!(do_describe(tcx, key))
)
);
let description =
@@ -328,7 +317,7 @@ pub(crate) fn create_query_frame<
// so exit to avoid infinite recursion.
None
} else {
- Some(key.default_span(*tcx))
+ Some(key.default_span(tcx))
};
let def_id = key.key_as_def_id();
let def_kind = if kind == dep_graph::DepKind::opt_def_kind {
@@ -342,7 +331,7 @@ pub(crate) fn create_query_frame<
let mut hasher = StableHasher::new();
std::mem::discriminant(&kind).hash_stable(&mut hcx, &mut hasher);
key.hash_stable(&mut hcx, &mut hasher);
- hasher.finish::<u64>()
+ hasher.finish::<Hash64>()
})
};
let ty_adt_id = key.ty_adt_id();
@@ -350,6 +339,34 @@ pub(crate) fn create_query_frame<
QueryStackFrame::new(description, span, def_id, def_kind, kind, ty_adt_id, hash)
}
+pub(crate) fn encode_query_results<'a, 'tcx, Q>(
+ query: Q::Config,
+ qcx: QueryCtxt<'tcx>,
+ encoder: &mut CacheEncoder<'a, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex,
+) where
+ Q: super::QueryConfigRestored<'tcx>,
+ Q::RestoredValue: Encodable<CacheEncoder<'a, 'tcx>>,
+{
+ let _timer =
+ qcx.profiler().verbose_generic_activity_with_arg("encode_query_results_for", query.name());
+
+ assert!(query.query_state(qcx).all_inactive());
+ let cache = query.query_cache(qcx);
+ cache.iter(&mut |key, value, dep_node| {
+ if query.cache_on_disk(qcx.tcx, &key) {
+ let dep_node = SerializedDepNodeIndex::new(dep_node.index());
+
+ // Record position of the cache entry.
+ query_result_index.push((dep_node, AbsoluteBytePos::new(encoder.position())));
+
+ // Encode the type check tables with the `SerializedDepNodeIndex`
+ // as tag.
+ encoder.encode_tagged(dep_node, &Q::restore(*value));
+ }
+ });
+}
+
fn try_load_from_on_disk_cache<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode)
where
Q: QueryConfig<QueryCtxt<'tcx>>,
@@ -364,8 +381,8 @@ where
}
}
-pub(crate) fn loadable_from_disk<'tcx>(tcx: QueryCtxt<'tcx>, id: SerializedDepNodeIndex) -> bool {
- if let Some(cache) = tcx.on_disk_cache().as_ref() {
+pub(crate) fn loadable_from_disk<'tcx>(tcx: TyCtxt<'tcx>, id: SerializedDepNodeIndex) -> bool {
+ if let Some(cache) = tcx.query_system.on_disk_cache.as_ref() {
cache.loadable_from_disk(id)
} else {
false
@@ -373,13 +390,27 @@ pub(crate) fn loadable_from_disk<'tcx>(tcx: QueryCtxt<'tcx>, id: SerializedDepNo
}
pub(crate) fn try_load_from_disk<'tcx, V>(
- tcx: QueryCtxt<'tcx>,
- id: SerializedDepNodeIndex,
+ tcx: TyCtxt<'tcx>,
+ prev_index: SerializedDepNodeIndex,
+ index: DepNodeIndex,
) -> Option<V>
where
V: for<'a> Decodable<CacheDecoder<'a, 'tcx>>,
{
- tcx.on_disk_cache().as_ref()?.try_load_query_result(*tcx, id)
+ let on_disk_cache = tcx.query_system.on_disk_cache.as_ref()?;
+
+ let prof_timer = tcx.prof.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 value = tcx
+ .dep_graph
+ .with_query_deserialization(|| on_disk_cache.try_load_query_result(tcx, prev_index));
+
+ prof_timer.finish_with_query_invocation_id(index.into());
+
+ value
}
fn force_from_dep_node<'tcx, Q>(query: Q, tcx: TyCtxt<'tcx>, dep_node: DepNode) -> bool
@@ -407,8 +438,7 @@ where
if let Some(key) = Q::Key::recover(tcx, &dep_node) {
#[cfg(debug_assertions)]
let _guard = tracing::span!(tracing::Level::TRACE, stringify!($name), ?key).entered();
- let tcx = QueryCtxt::from_tcx(tcx);
- force_query(query, tcx, key, dep_node);
+ force_query(query, QueryCtxt::new(tcx), key, dep_node);
true
} else {
false
@@ -417,10 +447,9 @@ where
pub(crate) fn query_callback<'tcx, Q>(is_anon: bool, is_eval_always: bool) -> DepKindStruct<'tcx>
where
- Q: QueryConfig<QueryCtxt<'tcx>> + Default,
- Q::Key: DepNodeParams<TyCtxt<'tcx>>,
+ Q: QueryConfigRestored<'tcx>,
{
- let fingerprint_style = Q::Key::fingerprint_style();
+ let fingerprint_style = <Q::Config as QueryConfig<QueryCtxt<'tcx>>>::Key::fingerprint_style();
if is_anon || !fingerprint_style.reconstructible() {
return DepKindStruct {
@@ -436,13 +465,25 @@ where
is_anon,
is_eval_always,
fingerprint_style,
- force_from_dep_node: Some(|tcx, dep_node| force_from_dep_node(Q::default(), tcx, dep_node)),
+ force_from_dep_node: Some(|tcx, dep_node| {
+ force_from_dep_node(Q::config(tcx), tcx, dep_node)
+ }),
try_load_from_on_disk_cache: Some(|tcx, dep_node| {
- try_load_from_on_disk_cache(Q::default(), tcx, dep_node)
+ try_load_from_on_disk_cache(Q::config(tcx), tcx, dep_node)
}),
}
}
+macro_rules! item_if_cached {
+ ([] $tokens:tt) => {};
+ ([(cache) $($rest:tt)*] { $($tokens:tt)* }) => {
+ $($tokens)*
+ };
+ ([$other:tt $($modifiers:tt)*] $tokens:tt) => {
+ item_if_cached! { [$($modifiers)*] $tokens }
+ };
+}
+
macro_rules! expand_if_cached {
([], $tokens:expr) => {{
None
@@ -455,168 +496,226 @@ macro_rules! expand_if_cached {
};
}
+/// Don't show the backtrace for query system by default
+/// use `RUST_BACKTRACE=full` to show all the backtraces
+#[inline(never)]
+pub fn __rust_begin_short_backtrace<F, T>(f: F) -> T
+where
+ F: FnOnce() -> T,
+{
+ let result = f();
+ std::hint::black_box(());
+ result
+}
+
// NOTE: `$V` isn't used here, but we still need to match on it so it can be passed to other macros
// invoked by `rustc_query_append`.
macro_rules! define_queries {
(
$($(#[$attr:meta])*
[$($modifiers:tt)*] fn $name:ident($($K:tt)*) -> $V:ty,)*) => {
- define_queries_struct! {
- input: ($(([$($modifiers)*] [$($attr)*] [$name]))*)
- }
- #[allow(nonstandard_style)]
- mod queries {
+ pub(crate) mod query_impl { $(pub mod $name {
+ use super::super::*;
use std::marker::PhantomData;
- $(
- #[derive(Copy, Clone, Default)]
- pub struct $name<'tcx> {
- data: PhantomData<&'tcx ()>
+ pub mod get_query_incr {
+ use super::*;
+
+ // Adding `__rust_end_short_backtrace` marker to backtraces so that we emit the frames
+ // when `RUST_BACKTRACE=1`, add a new mod with `$name` here is to allow duplicate naming
+ #[inline(never)]
+ pub fn __rust_end_short_backtrace<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ key: queries::$name::Key<'tcx>,
+ mode: QueryMode,
+ ) -> Option<Erase<queries::$name::Value<'tcx>>> {
+ get_query_incr(
+ QueryType::config(tcx),
+ QueryCtxt::new(tcx),
+ span,
+ key,
+ mode
+ )
}
- )*
- }
-
- $(impl<'tcx> QueryConfig<QueryCtxt<'tcx>> for queries::$name<'tcx> {
- type Key = query_keys::$name<'tcx>;
- type Value = Erase<query_values::$name<'tcx>>;
-
- #[inline(always)]
- fn name(self) -> &'static str {
- stringify!($name)
- }
-
- #[inline]
- fn format_value(self) -> fn(&Self::Value) -> String {
- |value| format!("{:?}", restore::<query_values::$name<'tcx>>(*value))
- }
-
- #[inline]
- fn cache_on_disk(self, tcx: TyCtxt<'tcx>, key: &Self::Key) -> bool {
- ::rustc_middle::query::cached::$name(tcx, key)
- }
-
- type Cache = query_storage::$name<'tcx>;
-
- #[inline(always)]
- fn query_state<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a QueryState<Self::Key, crate::dep_graph::DepKind>
- where QueryCtxt<'tcx>: 'a
- {
- &tcx.queries.$name
}
- #[inline(always)]
- fn query_cache<'a>(self, tcx: QueryCtxt<'tcx>) -> &'a Self::Cache
- where 'tcx:'a
- {
- &tcx.query_system.caches.$name
+ pub mod get_query_non_incr {
+ use super::*;
+
+ #[inline(never)]
+ pub fn __rust_end_short_backtrace<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ key: queries::$name::Key<'tcx>,
+ __mode: QueryMode,
+ ) -> Option<Erase<queries::$name::Value<'tcx>>> {
+ Some(get_query_non_incr(
+ QueryType::config(tcx),
+ QueryCtxt::new(tcx),
+ span,
+ key,
+ ))
+ }
}
- fn execute_query(self, tcx: TyCtxt<'tcx>, key: Self::Key) -> Self::Value {
- erase(tcx.$name(key))
+ pub fn dynamic_query<'tcx>() -> DynamicQuery<'tcx, queries::$name::Storage<'tcx>> {
+ DynamicQuery {
+ name: stringify!($name),
+ eval_always: is_eval_always!([$($modifiers)*]),
+ dep_kind: dep_graph::DepKind::$name,
+ handle_cycle_error: handle_cycle_error!([$($modifiers)*]),
+ query_state: offset_of!(QueryStates<'tcx> => $name),
+ query_cache: offset_of!(QueryCaches<'tcx> => $name),
+ cache_on_disk: |tcx, key| ::rustc_middle::query::cached::$name(tcx, key),
+ execute_query: |tcx, key| erase(tcx.$name(key)),
+ compute: |tcx, key| {
+ __rust_begin_short_backtrace(||
+ queries::$name::provided_to_erased(
+ tcx,
+ call_provider!([$($modifiers)*][tcx, $name, key])
+ )
+ )
+ },
+ can_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] true false),
+ try_load_from_disk: should_ever_cache_on_disk!([$($modifiers)*] {
+ |tcx, key, prev_index, index| {
+ if ::rustc_middle::query::cached::$name(tcx, key) {
+ let value = $crate::plumbing::try_load_from_disk::<
+ queries::$name::ProvidedValue<'tcx>
+ >(
+ tcx,
+ prev_index,
+ index,
+ );
+ value.map(|value| queries::$name::provided_to_erased(tcx, value))
+ } else {
+ None
+ }
+ }
+ } {
+ |_tcx, _key, _prev_index, _index| None
+ }),
+ value_from_cycle_error: |tcx, cycle| {
+ let result: queries::$name::Value<'tcx> = Value::from_cycle_error(tcx, cycle);
+ erase(result)
+ },
+ loadable_from_disk: |_tcx, _key, _index| {
+ should_ever_cache_on_disk!([$($modifiers)*] {
+ ::rustc_middle::query::cached::$name(_tcx, _key) &&
+ $crate::plumbing::loadable_from_disk(_tcx, _index)
+ } {
+ false
+ })
+ },
+ hash_result: hash_result!([$($modifiers)*][queries::$name::Value<'tcx>]),
+ format_value: |value| format!("{:?}", restore::<queries::$name::Value<'tcx>>(*value)),
+ }
}
- #[inline]
- #[allow(unused_variables)]
- fn compute(self, qcx: QueryCtxt<'tcx>, key: Self::Key) -> Self::Value {
- query_provided_to_value::$name(
- qcx.tcx,
- call_provider!([$($modifiers)*][qcx, $name, key])
- )
+ #[derive(Copy, Clone, Default)]
+ pub struct QueryType<'tcx> {
+ data: PhantomData<&'tcx ()>
}
- #[inline]
- fn try_load_from_disk(
- self,
- _qcx: QueryCtxt<'tcx>,
- _key: &Self::Key
- ) -> rustc_query_system::query::TryLoadFromDisk<QueryCtxt<'tcx>, Self::Value> {
- should_ever_cache_on_disk!([$($modifiers)*] {
- if ::rustc_middle::query::cached::$name(_qcx.tcx, _key) {
- Some(|qcx: QueryCtxt<'tcx>, dep_node| {
- let value = $crate::plumbing::try_load_from_disk::<query_provided::$name<'tcx>>(
- qcx,
- dep_node
- );
- value.map(|value| query_provided_to_value::$name(qcx.tcx, value))
- })
- } else {
- None
+ impl<'tcx> QueryConfigRestored<'tcx> for QueryType<'tcx> {
+ type RestoredValue = queries::$name::Value<'tcx>;
+ type Config = DynamicConfig<
+ 'tcx,
+ queries::$name::Storage<'tcx>,
+ { is_anon!([$($modifiers)*]) },
+ { depth_limit!([$($modifiers)*]) },
+ { feedable!([$($modifiers)*]) },
+ >;
+
+ #[inline(always)]
+ fn config(tcx: TyCtxt<'tcx>) -> Self::Config {
+ DynamicConfig {
+ dynamic: &tcx.query_system.dynamic_queries.$name,
}
- } {
- None
- })
- }
-
- #[inline]
- fn loadable_from_disk(
- self,
- _qcx: QueryCtxt<'tcx>,
- _key: &Self::Key,
- _index: SerializedDepNodeIndex,
- ) -> bool {
- should_ever_cache_on_disk!([$($modifiers)*] {
- self.cache_on_disk(_qcx.tcx, _key) &&
- $crate::plumbing::loadable_from_disk(_qcx, _index)
- } {
- false
- })
- }
+ }
- #[inline]
- fn value_from_cycle_error(
- self,
- tcx: TyCtxt<'tcx>,
- cycle: &[QueryInfo<DepKind>],
- ) -> Self::Value {
- let result: query_values::$name<'tcx> = Value::from_cycle_error(tcx, cycle);
- erase(result)
+ #[inline(always)]
+ fn restore(value: <Self::Config as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue {
+ restore::<queries::$name::Value<'tcx>>(value)
+ }
}
- #[inline(always)]
- fn anon(self) -> bool {
- is_anon!([$($modifiers)*])
+ pub fn try_collect_active_jobs<'tcx>(tcx: TyCtxt<'tcx>, qmap: &mut QueryMap<DepKind>) {
+ let make_query = |tcx, key| {
+ let kind = rustc_middle::dep_graph::DepKind::$name;
+ let name = stringify!($name);
+ $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
+ };
+ tcx.query_system.states.$name.try_collect_active_jobs(
+ tcx,
+ make_query,
+ qmap,
+ ).unwrap();
}
- #[inline(always)]
- fn eval_always(self) -> bool {
- is_eval_always!([$($modifiers)*])
+ pub fn alloc_self_profile_query_strings<'tcx>(tcx: TyCtxt<'tcx>, string_cache: &mut QueryKeyStringCache) {
+ $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
+ tcx,
+ stringify!($name),
+ &tcx.query_system.caches.$name,
+ string_cache,
+ )
}
- #[inline(always)]
- fn depth_limit(self) -> bool {
- depth_limit!([$($modifiers)*])
- }
+ item_if_cached! { [$($modifiers)*] {
+ pub fn encode_query_results<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ encoder: &mut CacheEncoder<'_, 'tcx>,
+ query_result_index: &mut EncodedDepNodeIndex
+ ) {
+ $crate::plumbing::encode_query_results::<query_impl::$name::QueryType<'tcx>>(
+ query_impl::$name::QueryType::config(tcx),
+ QueryCtxt::new(tcx),
+ encoder,
+ query_result_index,
+ )
+ }
+ }}
+ })*}
- #[inline(always)]
- fn feedable(self) -> bool {
- feedable!([$($modifiers)*])
+ pub(crate) fn engine(incremental: bool) -> QueryEngine {
+ if incremental {
+ QueryEngine {
+ $($name: query_impl::$name::get_query_incr::__rust_end_short_backtrace,)*
+ }
+ } else {
+ QueryEngine {
+ $($name: query_impl::$name::get_query_non_incr::__rust_end_short_backtrace,)*
+ }
}
+ }
- #[inline(always)]
- fn dep_kind(self) -> rustc_middle::dep_graph::DepKind {
- dep_graph::DepKind::$name
+ pub fn dynamic_queries<'tcx>() -> DynamicQueries<'tcx> {
+ DynamicQueries {
+ $(
+ $name: query_impl::$name::dynamic_query(),
+ )*
}
+ }
- #[inline(always)]
- fn handle_cycle_error(self) -> rustc_query_system::HandleCycleError {
- handle_cycle_error!([$($modifiers)*])
- }
+ // These arrays are used for iteration and can't be indexed by `DepKind`.
- #[inline(always)]
- fn hash_result(self) -> rustc_query_system::query::HashResult<Self::Value> {
- hash_result!([$($modifiers)*][query_values::$name<'tcx>])
- }
- })*
+ const TRY_COLLECT_ACTIVE_JOBS: &[for<'tcx> fn(TyCtxt<'tcx>, &mut QueryMap<DepKind>)] =
+ &[$(query_impl::$name::try_collect_active_jobs),*];
- $(impl<'tcx> QueryConfigRestored<'tcx> for queries::$name<'tcx> {
- type RestoredValue = query_values::$name<'tcx>;
+ const ALLOC_SELF_PROFILE_QUERY_STRINGS: &[
+ for<'tcx> fn(TyCtxt<'tcx>, &mut QueryKeyStringCache)
+ ] = &[$(query_impl::$name::alloc_self_profile_query_strings),*];
- #[inline(always)]
- fn restore(value: <Self as QueryConfig<QueryCtxt<'tcx>>>::Value) -> Self::RestoredValue {
- restore::<query_values::$name<'tcx>>(value)
- }
- })*
+ const ENCODE_QUERY_RESULTS: &[
+ Option<for<'tcx> fn(
+ TyCtxt<'tcx>,
+ &mut CacheEncoder<'_, 'tcx>,
+ &mut EncodedDepNodeIndex)
+ >
+ ] = &[$(expand_if_cached!([$($modifiers)*], query_impl::$name::encode_query_results)),*];
#[allow(nonstandard_style)]
mod query_callbacks {
@@ -676,164 +775,15 @@ macro_rules! define_queries {
}
$(pub(crate) fn $name<'tcx>()-> DepKindStruct<'tcx> {
- $crate::plumbing::query_callback::<queries::$name<'tcx>>(
+ $crate::plumbing::query_callback::<query_impl::$name::QueryType<'tcx>>(
is_anon!([$($modifiers)*]),
is_eval_always!([$($modifiers)*]),
)
})*
}
- mod query_structs {
- use rustc_middle::ty::TyCtxt;
- use $crate::plumbing::{QueryStruct, QueryCtxt};
- use $crate::profiling_support::QueryKeyStringCache;
- use rustc_query_system::query::QueryMap;
- use rustc_middle::dep_graph::DepKind;
-
- pub(super) const fn dummy_query_struct<'tcx>() -> QueryStruct<'tcx> {
- fn noop_try_collect_active_jobs(_: QueryCtxt<'_>, _: &mut QueryMap<DepKind>) -> Option<()> {
- None
- }
- fn noop_alloc_self_profile_query_strings(_: TyCtxt<'_>, _: &mut QueryKeyStringCache) {}
-
- QueryStruct {
- try_collect_active_jobs: noop_try_collect_active_jobs,
- alloc_self_profile_query_strings: noop_alloc_self_profile_query_strings,
- encode_query_results: None,
- }
- }
-
- pub(super) use dummy_query_struct as Null;
- pub(super) use dummy_query_struct as Red;
- pub(super) use dummy_query_struct as TraitSelect;
- pub(super) use dummy_query_struct as CompileCodegenUnit;
- pub(super) use dummy_query_struct as CompileMonoItem;
-
- $(
- pub(super) const fn $name<'tcx>() -> QueryStruct<'tcx> { QueryStruct {
- try_collect_active_jobs: |tcx, qmap| {
- let make_query = |tcx, key| {
- let kind = rustc_middle::dep_graph::DepKind::$name;
- let name = stringify!($name);
- $crate::plumbing::create_query_frame(tcx, rustc_middle::query::descs::$name, key, kind, name)
- };
- tcx.queries.$name.try_collect_active_jobs(
- tcx,
- make_query,
- qmap,
- )
- },
- alloc_self_profile_query_strings: |tcx, string_cache| {
- $crate::profiling_support::alloc_self_profile_query_strings_for_query_cache(
- tcx,
- stringify!($name),
- &tcx.query_system.caches.$name,
- string_cache,
- )
- },
- encode_query_results: expand_if_cached!([$($modifiers)*], |qcx, encoder, query_result_index|
- $crate::on_disk_cache::encode_query_results::<super::queries::$name<'tcx>>(
- super::queries::$name::default(),
- qcx,
- encoder,
- query_result_index,
- )
- ),
- }})*
- }
-
pub fn query_callbacks<'tcx>(arena: &'tcx Arena<'tcx>) -> &'tcx [DepKindStruct<'tcx>] {
arena.alloc_from_iter(make_dep_kind_array!(query_callbacks))
}
}
}
-
-use crate::{ExternProviders, OnDiskCache, Providers};
-
-impl<'tcx> Queries<'tcx> {
- pub fn new(
- local_providers: Providers,
- extern_providers: ExternProviders,
- on_disk_cache: Option<OnDiskCache<'tcx>>,
- ) -> Self {
- use crate::query_structs;
- Queries {
- local_providers: Box::new(local_providers),
- extern_providers: Box::new(extern_providers),
- query_structs: make_dep_kind_array!(query_structs).to_vec(),
- on_disk_cache,
- jobs: AtomicU64::new(1),
- ..Queries::default()
- }
- }
-}
-
-macro_rules! define_queries_struct {
- (
- input: ($(([$($modifiers:tt)*] [$($attr:tt)*] [$name:ident]))*)) => {
- #[derive(Default)]
- pub struct Queries<'tcx> {
- local_providers: Box<Providers>,
- extern_providers: Box<ExternProviders>,
- query_structs: Vec<$crate::plumbing::QueryStruct<'tcx>>,
- pub on_disk_cache: Option<OnDiskCache<'tcx>>,
- jobs: AtomicU64,
-
- $(
- $(#[$attr])*
- $name: QueryState<
- <queries::$name<'tcx> as QueryConfig<QueryCtxt<'tcx>>>::Key,
- rustc_middle::dep_graph::DepKind,
- >,
- )*
- }
-
- impl<'tcx> Queries<'tcx> {
- pub(crate) fn try_collect_active_jobs(
- &'tcx self,
- tcx: TyCtxt<'tcx>,
- ) -> Option<QueryMap<rustc_middle::dep_graph::DepKind>> {
- let tcx = QueryCtxt { tcx, queries: self };
- let mut jobs = QueryMap::default();
-
- for query in &self.query_structs {
- (query.try_collect_active_jobs)(tcx, &mut jobs);
- }
-
- Some(jobs)
- }
- }
-
- impl<'tcx> QueryEngine<'tcx> for Queries<'tcx> {
- fn as_any(&'tcx self) -> &'tcx dyn std::any::Any {
- let this = unsafe { std::mem::transmute::<&Queries<'_>, &Queries<'_>>(self) };
- this as _
- }
-
- fn try_mark_green(&'tcx self, tcx: TyCtxt<'tcx>, dep_node: &dep_graph::DepNode) -> bool {
- let qcx = QueryCtxt { tcx, queries: self };
- tcx.dep_graph.try_mark_green(qcx, dep_node).is_some()
- }
-
- $($(#[$attr])*
- #[inline(always)]
- #[tracing::instrument(level = "trace", skip(self, tcx))]
- fn $name(
- &'tcx self,
- tcx: TyCtxt<'tcx>,
- span: Span,
- key: query_keys::$name<'tcx>,
- mode: QueryMode,
- ) -> Option<Erase<query_values::$name<'tcx>>> {
- let qcx = QueryCtxt { tcx, queries: self };
- get_query(
- queries::$name::default(),
- qcx,
- span,
- key,
- mode
- )
- })*
- }
- };
-}
diff --git a/compiler/rustc_query_impl/src/profiling_support.rs b/compiler/rustc_query_impl/src/profiling_support.rs
index 4743170e9..fbc6db93e 100644
--- a/compiler/rustc_query_impl/src/profiling_support.rs
+++ b/compiler/rustc_query_impl/src/profiling_support.rs
@@ -1,24 +1,13 @@
-use crate::QueryCtxt;
use measureme::{StringComponent, StringId};
-use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfiler;
use rustc_hir::def_id::{CrateNum, DefId, DefIndex, LocalDefId, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
-use rustc_middle::ty::{TyCtxt, WithOptConstParam};
+use rustc_middle::query::plumbing::QueryKeyStringCache;
+use rustc_middle::ty::TyCtxt;
use rustc_query_system::query::QueryCache;
use std::fmt::Debug;
use std::io::Write;
-pub(crate) struct QueryKeyStringCache {
- def_id_cache: FxHashMap<DefId, StringId>,
-}
-
-impl QueryKeyStringCache {
- fn new() -> QueryKeyStringCache {
- QueryKeyStringCache { def_id_cache: Default::default() }
- }
-}
-
struct QueryKeyStringBuilder<'p, 'tcx> {
profiler: &'p SelfProfiler,
tcx: TyCtxt<'tcx>,
@@ -151,37 +140,6 @@ impl SpecIntoSelfProfilingString for LocalDefId {
}
}
-impl<T: SpecIntoSelfProfilingString> SpecIntoSelfProfilingString for WithOptConstParam<T> {
- 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:
- //
- // "WithOptConstParam { did: foo::bar, const_param_did: Some(foo::baz) }"
- // becomes "(foo::bar, foo::baz)" and
- // "WithOptConstParam { did: foo::bar, const_param_did: None }"
- // becomes "(foo::bar, _)".
-
- let did = StringComponent::Ref(self.did.to_self_profile_string(builder));
-
- let const_param_did = if let Some(const_param_did) = self.const_param_did {
- let const_param_did = builder.def_id_to_string_id(const_param_did);
- StringComponent::Ref(const_param_did)
- } else {
- StringComponent::Value("_")
- };
-
- let components = [
- StringComponent::Value("("),
- did,
- StringComponent::Value(", "),
- const_param_did,
- StringComponent::Value(")"),
- ];
-
- builder.profiler.alloc_string(&components[..])
- }
-}
-
impl<T0, T1> SpecIntoSelfProfilingString for (T0, T1)
where
T0: SpecIntoSelfProfilingString,
@@ -231,7 +189,7 @@ pub(crate) fn alloc_self_profile_query_strings_for_query_cache<'tcx, C>(
// locked while doing so. Instead we copy out the
// `(query_key, dep_node_index)` pairs and release the lock again.
let mut query_keys_and_indices = Vec::new();
- query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((k.clone(), i)));
+ query_cache.iter(&mut |k, _, i| query_keys_and_indices.push((*k, i)));
// Now actually allocate the strings. If allocating the strings
// generates new entries in the query cache, we'll miss them but
@@ -284,9 +242,8 @@ pub fn alloc_self_profile_query_strings(tcx: TyCtxt<'_>) {
}
let mut string_cache = QueryKeyStringCache::new();
- let queries = QueryCtxt::from_tcx(tcx);
- for query in &queries.queries.query_structs {
- (query.alloc_self_profile_query_strings)(tcx, &mut string_cache);
+ for alloc in super::ALLOC_SELF_PROFILE_QUERY_STRINGS.iter() {
+ alloc(tcx, &mut string_cache)
}
}
diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml
index 12b4a1143..e02cf38b6 100644
--- a/compiler/rustc_query_system/Cargo.toml
+++ b/compiler/rustc_query_system/Cargo.toml
@@ -7,11 +7,11 @@ edition = "2021"
[dependencies]
parking_lot = "0.11"
-rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_query_system/messages.ftl b/compiler/rustc_query_system/messages.ftl
index 870e82403..49b423d1a 100644
--- a/compiler/rustc_query_system/messages.ftl
+++ b/compiler/rustc_query_system/messages.ftl
@@ -1,30 +1,30 @@
-query_system_reentrant = internal compiler error: re-entrant incremental verify failure, suppressing message
-
-query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node}
- .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile
-
-query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information
-query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information
-
query_system_cycle = cycle detected when {$stack_bottom}
-query_system_cycle_usage = cycle used when {$usage}
+query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
-query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
+query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
+query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle
+query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
query_system_cycle_stack_middle = ...which requires {$desc}...
query_system_cycle_stack_multiple = ...which again requires {$stack_bottom}, completing the cycle
-query_system_cycle_recursive_ty_alias = type aliases cannot be recursive
-query_system_cycle_recursive_ty_alias_help1 = consider using a struct, enum, or union instead to break the cycle
-query_system_cycle_recursive_ty_alias_help2 = see <https://doc.rust-lang.org/reference/types.html#recursive-types> for more information
+query_system_cycle_stack_single = ...which immediately requires {$stack_bottom} again
-query_system_cycle_recursive_trait_alias = trait aliases cannot be recursive
+query_system_cycle_usage = cycle used when {$usage}
query_system_cycle_which_requires = ...which requires {$desc}...
+query_system_increment_compilation = internal compiler error: encountered incremental compilation error with {$dep_node}
+ .help = This is a known issue with the compiler. Run {$run_cmd} to allow your project to compile
+
+query_system_increment_compilation_note1 = Please follow the instructions below to create a bug report with the provided information
+query_system_increment_compilation_note2 = See <https://github.com/rust-lang/rust/issues/84970> for more information
+
+query_system_layout_of_depth = query depth increased by {$depth} when {$desc}
+
query_system_query_overflow = queries overflow the depth limit!
.help = consider increasing the recursion limit by adding a `#![recursion_limit = "{$suggested_limit}"]` attribute to your crate (`{$crate_name}`)
-query_system_layout_of_depth = query depth increased by {$depth} when {$desc}
+query_system_reentrant = internal compiler error: reentrant incremental verify failure, suppressing message
diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs
index a9a2e6dd0..c0d7386dd 100644
--- a/compiler/rustc_query_system/src/dep_graph/graph.rs
+++ b/compiler/rustc_query_system/src/dep_graph/graph.rs
@@ -6,7 +6,7 @@ use rustc_data_structures::sharded::{self, Sharded};
use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
use rustc_data_structures::steal::Steal;
use rustc_data_structures::sync::{AtomicU32, AtomicU64, Lock, Lrc, Ordering};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder};
use smallvec::{smallvec, SmallVec};
use std::assert_matches::assert_matches;
@@ -249,7 +249,7 @@ impl<K: DepKind> DepGraph<K> {
/// get an ICE. Normally, we would have tried (and failed) to mark
/// some other query green (e.g. `item_children`) which was used
/// to obtain `C`, which would prevent us from ever trying to force
- /// a non-existent `D`.
+ /// a nonexistent `D`.
///
/// It might be possible to enforce that all `DepNode`s read during
/// deserialization already exist in the previous `DepGraph`. In
@@ -354,24 +354,20 @@ impl<K: DepKind> DepGraphData<K> {
- dep-node: {key:?}"
);
- let task_deps = if cx.dep_context().is_eval_always(key.kind) {
- None
+ let with_deps = |task_deps| K::with_deps(task_deps, || task(cx, arg));
+ let (result, edges) = if cx.dep_context().is_eval_always(key.kind) {
+ (with_deps(TaskDepsRef::EvalAlways), smallvec![])
} else {
- Some(Lock::new(TaskDeps {
+ let task_deps = Lock::new(TaskDeps {
#[cfg(debug_assertions)]
node: Some(key),
reads: SmallVec::new(),
read_set: Default::default(),
phantom_data: PhantomData,
- }))
+ });
+ (with_deps(TaskDepsRef::Allow(&task_deps)), task_deps.into_inner().reads)
};
- let task_deps_ref =
- task_deps.as_ref().map(TaskDepsRef::Allow).unwrap_or(TaskDepsRef::EvalAlways);
-
- let result = K::with_deps(task_deps_ref, || task(cx, arg));
- let edges = task_deps.map_or_else(|| smallvec![], |lock| lock.into_inner().reads);
-
let dcx = cx.dep_context();
let hashing_timer = dcx.profiler().incr_result_hashing();
let current_fingerprint =
@@ -660,7 +656,7 @@ impl<K: DepKind> DepGraphData<K> {
/// current compilation session. Used in various assertions
#[inline]
pub fn is_index_green(&self, prev_index: SerializedDepNodeIndex) -> bool {
- self.colors.get(prev_index).map_or(false, |c| c.is_green())
+ self.colors.get(prev_index).is_some_and(|c| c.is_green())
}
#[inline]
@@ -681,7 +677,7 @@ impl<K: DepKind> DepGraphData<K> {
impl<K: DepKind> DepGraph<K> {
#[inline]
pub fn dep_node_exists(&self, dep_node: &DepNode<K>) -> bool {
- self.data.as_ref().map_or(false, |data| data.dep_node_exists(dep_node))
+ self.data.as_ref().is_some_and(|data| data.dep_node_exists(dep_node))
}
/// Checks whether a previous work product exists for `v` and, if
@@ -959,7 +955,7 @@ impl<K: DepKind> DepGraph<K> {
/// Returns true if the given node has been marked as green during the
/// current compilation session. Used in various assertions
pub fn is_green(&self, dep_node: &DepNode<K>) -> bool {
- self.node_color(dep_node).map_or(false, |c| c.is_green())
+ self.node_color(dep_node).is_some_and(|c| c.is_green())
}
/// This method loads all on-disk cacheable query results into memory, so
@@ -1236,76 +1232,48 @@ impl<K: DepKind> CurrentDepGraph<K> {
self.node_intern_event_id.map(|eid| profiler.generic_activity_with_event_id(eid));
if let Some(prev_index) = prev_graph.node_to_index_opt(&key) {
+ let get_dep_node_index = |color, fingerprint| {
+ if print_status {
+ eprintln!("[task::{color:}] {key:?}");
+ }
+
+ let mut prev_index_to_index = self.prev_index_to_index.lock();
+
+ let dep_node_index = match prev_index_to_index[prev_index] {
+ Some(dep_node_index) => dep_node_index,
+ None => {
+ let dep_node_index =
+ self.encoder.borrow().send(profiler, key, fingerprint, edges);
+ prev_index_to_index[prev_index] = Some(dep_node_index);
+ dep_node_index
+ }
+ };
+
+ #[cfg(debug_assertions)]
+ self.record_edge(dep_node_index, key, fingerprint);
+
+ dep_node_index
+ };
+
// Determine the color and index of the new `DepNode`.
if let Some(fingerprint) = fingerprint {
if fingerprint == prev_graph.fingerprint_by_index(prev_index) {
- if print_status {
- eprintln!("[task::green] {key:?}");
- }
-
// This is a green node: it existed in the previous compilation,
// its query was re-executed, and it has the same result as before.
- let mut prev_index_to_index = self.prev_index_to_index.lock();
-
- let dep_node_index = match prev_index_to_index[prev_index] {
- Some(dep_node_index) => dep_node_index,
- None => {
- let dep_node_index =
- self.encoder.borrow().send(profiler, key, fingerprint, edges);
- prev_index_to_index[prev_index] = Some(dep_node_index);
- dep_node_index
- }
- };
-
- #[cfg(debug_assertions)]
- self.record_edge(dep_node_index, key, fingerprint);
+ let dep_node_index = get_dep_node_index("green", fingerprint);
(dep_node_index, Some((prev_index, DepNodeColor::Green(dep_node_index))))
} else {
- if print_status {
- eprintln!("[task::red] {key:?}");
- }
-
// This is a red node: it existed in the previous compilation, its query
// was re-executed, but it has a different result from before.
- let mut prev_index_to_index = self.prev_index_to_index.lock();
-
- let dep_node_index = match prev_index_to_index[prev_index] {
- Some(dep_node_index) => dep_node_index,
- None => {
- let dep_node_index =
- self.encoder.borrow().send(profiler, key, fingerprint, edges);
- prev_index_to_index[prev_index] = Some(dep_node_index);
- dep_node_index
- }
- };
-
- #[cfg(debug_assertions)]
- self.record_edge(dep_node_index, key, fingerprint);
+ let dep_node_index = get_dep_node_index("red", fingerprint);
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
}
} else {
- if print_status {
- eprintln!("[task::unknown] {key:?}");
- }
-
// This is a red node, effectively: it existed in the previous compilation
// session, its query was re-executed, but it doesn't compute a result hash
// (i.e. it represents a `no_hash` query), so we have no way of determining
// whether or not the result was the same as before.
- let mut prev_index_to_index = self.prev_index_to_index.lock();
-
- let dep_node_index = match prev_index_to_index[prev_index] {
- Some(dep_node_index) => dep_node_index,
- None => {
- let dep_node_index =
- self.encoder.borrow().send(profiler, key, Fingerprint::ZERO, edges);
- prev_index_to_index[prev_index] = Some(dep_node_index);
- dep_node_index
- }
- };
-
- #[cfg(debug_assertions)]
- self.record_edge(dep_node_index, key, Fingerprint::ZERO);
+ let dep_node_index = get_dep_node_index("unknown", Fingerprint::ZERO);
(dep_node_index, Some((prev_index, DepNodeColor::Red)))
}
} else {
diff --git a/compiler/rustc_query_system/src/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs
index 27b3b5e13..5cbc6bf8f 100644
--- a/compiler/rustc_query_system/src/dep_graph/query.rs
+++ b/compiler/rustc_query_system/src/dep_graph/query.rs
@@ -1,6 +1,6 @@
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::graph::implementation::{Direction, Graph, NodeIndex, INCOMING};
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use super::{DepKind, DepNode, DepNodeIndex};
@@ -24,10 +24,7 @@ impl<K: DepKind> DepGraphQuery<K> {
pub fn push(&mut self, index: DepNodeIndex, node: DepNode<K>, edges: &[DepNodeIndex]) {
let source = self.graph.add_node(node);
- if index.index() >= self.dep_index_to_index.len() {
- self.dep_index_to_index.resize(index.index() + 1, None);
- }
- self.dep_index_to_index[index] = Some(source);
+ self.dep_index_to_index.insert(index, source);
self.indices.insert(node, source);
for &target in edges.iter() {
diff --git a/compiler/rustc_query_system/src/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs
index 3d19a8491..edddfda62 100644
--- a/compiler/rustc_query_system/src/dep_graph/serialized.rs
+++ b/compiler/rustc_query_system/src/dep_graph/serialized.rs
@@ -18,7 +18,7 @@ use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::FxHashMap;
use rustc_data_structures::profiling::SelfProfilerRef;
use rustc_data_structures::sync::Lock;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use rustc_serialize::opaque::{FileEncodeResult, FileEncoder, IntEncodedWithFixedSize, MemDecoder};
use rustc_serialize::{Decodable, Decoder, Encodable};
use smallvec::SmallVec;
@@ -94,21 +94,19 @@ impl<'a, K: DepKind + Decodable<MemDecoder<'a>>> Decodable<MemDecoder<'a>>
{
#[instrument(level = "debug", skip(d))]
fn decode(d: &mut MemDecoder<'a>) -> SerializedDepGraph<K> {
- let start_position = d.position();
-
// The last 16 bytes are the node count and edge count.
debug!("position: {:?}", d.position());
- d.set_position(d.data.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE);
+ let (node_count, edge_count) =
+ d.with_position(d.len() - 2 * IntEncodedWithFixedSize::ENCODED_SIZE, |d| {
+ debug!("position: {:?}", d.position());
+ let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+ let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
+ (node_count, edge_count)
+ });
debug!("position: {:?}", d.position());
- let node_count = IntEncodedWithFixedSize::decode(d).0 as usize;
- let edge_count = IntEncodedWithFixedSize::decode(d).0 as usize;
debug!(?node_count, ?edge_count);
- debug!("position: {:?}", d.position());
- d.set_position(start_position);
- debug!("position: {:?}", d.position());
-
let mut nodes = IndexVec::with_capacity(node_count);
let mut fingerprints = IndexVec::with_capacity(node_count);
let mut edge_list_indices = IndexVec::with_capacity(node_count);
diff --git a/compiler/rustc_query_system/src/ich/impls_syntax.rs b/compiler/rustc_query_system/src/ich/impls_syntax.rs
index 0bc811eb0..e673d5b8c 100644
--- a/compiler/rustc_query_system/src/ich/impls_syntax.rs
+++ b/compiler/rustc_query_system/src/ich/impls_syntax.rs
@@ -24,7 +24,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
.iter()
.filter(|attr| {
!attr.is_doc_comment()
- && !attr.ident().map_or(false, |ident| hcx.is_ignored_attr(ident.name))
+ && !attr.ident().is_some_and(|ident| hcx.is_ignored_attr(ident.name))
})
.collect();
@@ -38,7 +38,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for [ast::Attribute] {
impl<'ctx> rustc_ast::HashStableContext for StableHashingContext<'ctx> {
fn hash_attr(&mut self, attr: &ast::Attribute, hasher: &mut StableHasher) {
// Make sure that these have been filtered out.
- debug_assert!(!attr.ident().map_or(false, |ident| self.is_ignored_attr(ident.name)));
+ debug_assert!(!attr.ident().is_some_and(|ident| self.is_ignored_attr(ident.name)));
debug_assert!(!attr.is_doc_comment());
let ast::Attribute { kind, id: _, style, span } = attr;
@@ -75,7 +75,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for SourceFile {
ref normalized_pos,
} = *self;
- (name_hash as u64).hash_stable(hcx, hasher);
+ name_hash.hash_stable(hcx, hasher);
src_hash.hash_stable(hcx, hasher);
diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs
index bb812b006..8c9e9cfad 100644
--- a/compiler/rustc_query_system/src/lib.rs
+++ b/compiler/rustc_query_system/src/lib.rs
@@ -16,7 +16,7 @@ extern crate rustc_data_structures;
extern crate rustc_macros;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
pub mod cache;
pub mod dep_graph;
diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs
index 29f6a07e8..9a09f516e 100644
--- a/compiler/rustc_query_system/src/query/caches.rs
+++ b/compiler/rustc_query_system/src/query/caches.rs
@@ -5,7 +5,7 @@ use rustc_data_structures::sharded;
#[cfg(parallel_compiler)]
use rustc_data_structures::sharded::Sharded;
use rustc_data_structures::sync::Lock;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_index::{Idx, IndexVec};
use std::fmt::Debug;
use std::hash::Hash;
use std::marker::PhantomData;
diff --git a/compiler/rustc_query_system/src/query/config.rs b/compiler/rustc_query_system/src/query/config.rs
index c8d779385..7e47d7012 100644
--- a/compiler/rustc_query_system/src/query/config.rs
+++ b/compiler/rustc_query_system/src/query/config.rs
@@ -4,6 +4,7 @@ use crate::dep_graph::{DepNode, DepNodeParams, SerializedDepNodeIndex};
use crate::error::HandleCycleError;
use crate::ich::StableHashingContext;
use crate::query::caches::QueryCache;
+use crate::query::DepNodeIndex;
use crate::query::{QueryContext, QueryInfo, QueryState};
use rustc_data_structures::fingerprint::Fingerprint;
@@ -12,8 +13,6 @@ use std::hash::Hash;
pub type HashResult<V> = Option<fn(&mut StableHashingContext<'_>, &V) -> Fingerprint>;
-pub type TryLoadFromDisk<Qcx, V> = Option<fn(Qcx, SerializedDepNodeIndex) -> Option<V>>;
-
pub trait QueryConfig<Qcx: QueryContext>: Copy {
fn name(self) -> &'static str;
@@ -43,7 +42,13 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
fn compute(self, tcx: Qcx, key: Self::Key) -> Self::Value;
- fn try_load_from_disk(self, qcx: Qcx, idx: &Self::Key) -> TryLoadFromDisk<Qcx, Self::Value>;
+ fn try_load_from_disk(
+ self,
+ tcx: Qcx,
+ key: &Self::Key,
+ prev_index: SerializedDepNodeIndex,
+ index: DepNodeIndex,
+ ) -> Option<Self::Value>;
fn loadable_from_disk(self, qcx: Qcx, key: &Self::Key, idx: SerializedDepNodeIndex) -> bool;
@@ -63,7 +68,7 @@ pub trait QueryConfig<Qcx: QueryContext>: Copy {
fn handle_cycle_error(self) -> HandleCycleError;
fn hash_result(self) -> HashResult<Self::Value>;
- // Just here for convernience and checking that the key matches the kind, don't override this.
+ // Just here for convenience and checking that the key matches the kind, don't override this.
fn construct_dep_node(self, tcx: Qcx::DepContext, key: &Self::Key) -> DepNode<Qcx::DepKind> {
DepNode::construct(tcx, self.dep_kind(), key)
}
diff --git a/compiler/rustc_query_system/src/query/job.rs b/compiler/rustc_query_system/src/query/job.rs
index a534b5407..f45f7ca5d 100644
--- a/compiler/rustc_query_system/src/query/job.rs
+++ b/compiler/rustc_query_system/src/query/job.rs
@@ -22,7 +22,7 @@ use {
rustc_data_structures::fx::FxHashSet,
rustc_data_structures::sync::Lock,
rustc_data_structures::sync::Lrc,
- rustc_data_structures::{jobserver, OnDrop},
+ rustc_data_structures::{defer, jobserver},
rustc_span::DUMMY_SP,
std::iter,
std::process,
@@ -530,7 +530,7 @@ fn remove_cycle<D: DepKind>(
/// all active queries for cycles before finally resuming all the waiters at once.
#[cfg(parallel_compiler)]
pub fn deadlock<D: DepKind>(query_map: QueryMap<D>, registry: &rayon_core::Registry) {
- let on_panic = OnDrop(|| {
+ let on_panic = defer(|| {
eprintln!("deadlock handler panicked, aborting process");
process::abort();
});
@@ -633,7 +633,7 @@ pub fn print_query_stack<Qcx: QueryContext>(
};
let mut diag = Diagnostic::new(
Level::FailureNote,
- &format!("#{} [{:?}] {}", i, query_info.query.dep_kind, query_info.query.description),
+ format!("#{} [{:?}] {}", i, query_info.query.dep_kind, query_info.query.description),
);
diag.span = query_info.job.span.into();
handler.force_print_diagnostic(diag);
diff --git a/compiler/rustc_query_system/src/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs
index 312b0e168..f7619d75b 100644
--- a/compiler/rustc_query_system/src/query/mod.rs
+++ b/compiler/rustc_query_system/src/query/mod.rs
@@ -12,10 +12,11 @@ pub use self::caches::{
};
mod config;
-pub use self::config::{HashResult, QueryConfig, TryLoadFromDisk};
+pub use self::config::{HashResult, QueryConfig};
use crate::dep_graph::DepKind;
use crate::dep_graph::{DepNodeIndex, HasDepContext, SerializedDepNodeIndex};
+use rustc_data_structures::stable_hasher::Hash64;
use rustc_data_structures::sync::Lock;
use rustc_errors::Diagnostic;
use rustc_hir::def::DefKind;
@@ -37,7 +38,7 @@ pub struct QueryStackFrame<D: DepKind> {
/// This hash is used to deterministically pick
/// a query to remove cycles in the parallel compiler.
#[cfg(parallel_compiler)]
- hash: u64,
+ hash: Hash64,
}
impl<D: DepKind> QueryStackFrame<D> {
@@ -49,7 +50,7 @@ impl<D: DepKind> QueryStackFrame<D> {
def_kind: Option<DefKind>,
dep_kind: D,
ty_adt_id: Option<DefId>,
- _hash: impl FnOnce() -> u64,
+ _hash: impl FnOnce() -> Hash64,
) -> Self {
Self {
description,
diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs
index 20310483d..730e4c8d3 100644
--- a/compiler/rustc_query_system/src/query/plumbing.rs
+++ b/compiler/rustc_query_system/src/query/plumbing.rs
@@ -236,7 +236,7 @@ pub(crate) struct CycleError<D: DepKind> {
/// It returns the shard index and a lock guard to the shard,
/// which will be used if the query is not in the cache and we need
/// to compute it.
-#[inline]
+#[inline(always)]
pub fn try_get_cached<Tcx, C>(tcx: Tcx, cache: &C, key: &C::Key) -> Option<C::Value>
where
C: QueryCache,
@@ -312,7 +312,7 @@ where
}
#[inline(never)]
-fn try_execute_query<Q, Qcx>(
+fn try_execute_query<Q, Qcx, const INCR: bool>(
query: Q,
qcx: Qcx,
span: Span,
@@ -355,7 +355,7 @@ where
// Drop the lock before we start executing the query
drop(state_lock);
- execute_job(query, qcx, state, key, id, dep_node)
+ execute_job::<_, _, INCR>(query, qcx, state, key, id, dep_node)
}
Entry::Occupied(mut entry) => {
match entry.get_mut() {
@@ -383,7 +383,7 @@ where
}
#[inline(always)]
-fn execute_job<Q, Qcx>(
+fn execute_job<Q, Qcx, const INCR: bool>(
query: Q,
qcx: Qcx,
state: &QueryState<Q::Key, Qcx::DepKind>,
@@ -398,9 +398,19 @@ where
// Use `JobOwner` so the query will be poisoned if executing it panics.
let job_owner = JobOwner { state, key };
- let (result, dep_node_index) = match qcx.dep_context().dep_graph().data() {
- None => execute_job_non_incr(query, qcx, key, id),
- Some(data) => execute_job_incr(query, qcx, data, key, dep_node, id),
+ debug_assert_eq!(qcx.dep_context().dep_graph().is_fully_enabled(), INCR);
+
+ let (result, dep_node_index) = if INCR {
+ execute_job_incr(
+ query,
+ qcx,
+ qcx.dep_context().dep_graph().data().unwrap(),
+ key,
+ dep_node,
+ id,
+ )
+ } else {
+ execute_job_non_incr(query, qcx, key, id)
};
let cache = query.query_cache(qcx);
@@ -410,10 +420,35 @@ where
// as its feeding query had. So if the fed query is red, so is its feeder, which will
// get evaluated first, and re-feed the query.
if let Some((cached_result, _)) = cache.lookup(&key) {
- panic!(
- "fed query later has its value computed. The already cached value: {}",
- (query.format_value())(&cached_result)
- );
+ let Some(hasher) = query.hash_result() else {
+ panic!(
+ "no_hash fed query later has its value computed.\n\
+ Remove `no_hash` modifier to allow recomputation.\n\
+ The already cached value: {}",
+ (query.format_value())(&cached_result)
+ );
+ };
+
+ let (old_hash, new_hash) = qcx.dep_context().with_stable_hashing_context(|mut hcx| {
+ (hasher(&mut hcx, &cached_result), hasher(&mut hcx, &result))
+ });
+ let formatter = query.format_value();
+ if old_hash != new_hash {
+ // We have an inconsistency. This can happen if one of the two
+ // results is tainted by errors. In this case, delay a bug to
+ // ensure compilation is doomed.
+ qcx.dep_context().sess().delay_span_bug(
+ DUMMY_SP,
+ format!(
+ "Computed query value for {:?}({:?}) is inconsistent with fed value,\n\
+ computed={:#?}\nfed={:#?}",
+ query.dep_kind(),
+ key,
+ formatter(&result),
+ formatter(&cached_result),
+ ),
+ );
+ }
}
}
job_owner.complete(cache, result, dep_node_index);
@@ -545,59 +580,44 @@ where
// 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(qcx, &key) {
- 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 = qcx
- .dep_context()
- .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(
- qcx.dep_context().sess().opts.unstable_opts.query_dep_graph,
- ) {
- dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
- }
-
- let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index);
- // If `-Zincremental-verify-ich` is specified, re-hash results from
- // the cache and make sure that they have the expected fingerprint.
- //
- // If not, we still seek to verify a subset of fingerprints loaded
- // from disk. Re-hashing results is fairly expensive, so we can't
- // currently afford to verify every hash. This subset should still
- // give us some coverage of potential bugs though.
- let try_verify = prev_fingerprint.as_value().1 % 32 == 0;
- if std::intrinsics::unlikely(
- try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
- ) {
- incremental_verify_ich(
- *qcx.dep_context(),
- dep_graph_data,
- &result,
- prev_dep_node_index,
- query.hash_result(),
- query.format_value(),
- );
- }
+ if let Some(result) = query.try_load_from_disk(qcx, key, prev_dep_node_index, dep_node_index) {
+ if std::intrinsics::unlikely(qcx.dep_context().sess().opts.unstable_opts.query_dep_graph) {
+ dep_graph_data.mark_debug_loaded_from_disk(*dep_node)
+ }
- return Some((result, dep_node_index));
+ let prev_fingerprint = dep_graph_data.prev_fingerprint_of(prev_dep_node_index);
+ // If `-Zincremental-verify-ich` is specified, re-hash results from
+ // the cache and make sure that they have the expected fingerprint.
+ //
+ // If not, we still seek to verify a subset of fingerprints loaded
+ // from disk. Re-hashing results is fairly expensive, so we can't
+ // currently afford to verify every hash. This subset should still
+ // give us some coverage of potential bugs though.
+ let try_verify = prev_fingerprint.split().1.as_u64() % 32 == 0;
+ if std::intrinsics::unlikely(
+ try_verify || qcx.dep_context().sess().opts.unstable_opts.incremental_verify_ich,
+ ) {
+ incremental_verify_ich(
+ *qcx.dep_context(),
+ dep_graph_data,
+ &result,
+ prev_dep_node_index,
+ query.hash_result(),
+ query.format_value(),
+ );
}
- // We always expect to find a cached result for things that
- // can be forced from `DepNode`.
- debug_assert!(
- !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
- "missing on-disk cache entry for reconstructible {dep_node:?}"
- );
+ return Some((result, dep_node_index));
}
+ // We always expect to find a cached result for things that
+ // can be forced from `DepNode`.
+ debug_assert!(
+ !query.cache_on_disk(*qcx.dep_context(), key)
+ || !qcx.dep_context().fingerprint_style(dep_node.kind).reconstructible(),
+ "missing on-disk cache entry for {dep_node:?}"
+ );
+
// Sanity check for the logic in `ensure`: if the node is green and the result loadable,
// we should actually be able to load it.
debug_assert!(
@@ -691,7 +711,7 @@ fn incremental_verify_ich_failed<Tcx>(
// which may result in another fingerprint mismatch while we're in the middle
// of processing this one. To avoid a double-panic (which kills the process
// before we can print out the query static), we print out a terse
- // but 'safe' message if we detect a re-entrant call to this method.
+ // but 'safe' message if we detect a reentrant call to this method.
thread_local! {
static INSIDE_VERIFY_PANIC: Cell<bool> = const { Cell::new(false) };
};
@@ -780,7 +800,18 @@ pub enum QueryMode {
}
#[inline(always)]
-pub fn get_query<Q, Qcx>(
+pub fn get_query_non_incr<Q, Qcx>(query: Q, qcx: Qcx, span: Span, key: Q::Key) -> Q::Value
+where
+ Q: QueryConfig<Qcx>,
+ Qcx: QueryContext,
+{
+ debug_assert!(!qcx.dep_context().dep_graph().is_fully_enabled());
+
+ ensure_sufficient_stack(|| try_execute_query::<Q, Qcx, false>(query, qcx, span, key, None).0)
+}
+
+#[inline(always)]
+pub fn get_query_incr<Q, Qcx>(
query: Q,
qcx: Qcx,
span: Span,
@@ -791,6 +822,8 @@ where
Q: QueryConfig<Qcx>,
Qcx: QueryContext,
{
+ debug_assert!(qcx.dep_context().dep_graph().is_fully_enabled());
+
let dep_node = if let QueryMode::Ensure { check_cache } = mode {
let (must_run, dep_node) = ensure_must_run(query, qcx, &key, check_cache);
if !must_run {
@@ -801,8 +834,9 @@ where
None
};
- let (result, dep_node_index) =
- ensure_sufficient_stack(|| try_execute_query(query, qcx, span, key, dep_node));
+ let (result, dep_node_index) = ensure_sufficient_stack(|| {
+ try_execute_query::<_, _, true>(query, qcx, span, key, dep_node)
+ });
if let Some(dep_node_index) = dep_node_index {
qcx.dep_context().dep_graph().read_index(dep_node_index)
}
@@ -827,5 +861,7 @@ pub fn force_query<Q, Qcx>(
debug_assert!(!query.anon());
- ensure_sufficient_stack(|| try_execute_query(query, qcx, DUMMY_SP, key, Some(dep_node)));
+ ensure_sufficient_stack(|| {
+ try_execute_query::<_, _, true>(query, qcx, DUMMY_SP, key, Some(dep_node))
+ });
}
diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml
index 5c4ec44d2..46da0aa28 100644
--- a/compiler/rustc_resolve/Cargo.toml
+++ b/compiler/rustc_resolve/Cargo.toml
@@ -7,7 +7,7 @@ edition = "2021"
[dependencies]
bitflags = "1.2.1"
-pulldown-cmark = { version = "0.9.2", default-features = false }
+pulldown-cmark = { version = "0.9.3", default-features = false }
rustc_arena = { path = "../rustc_arena" }
rustc_ast = { path = "../rustc_ast" }
rustc_ast_pretty = { path = "../rustc_ast_pretty" }
@@ -16,6 +16,7 @@ rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_expand = { path = "../rustc_expand" }
rustc_feature = { path = "../rustc_feature" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_hir = { path = "../rustc_hir" }
rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
diff --git a/compiler/rustc_resolve/messages.ftl b/compiler/rustc_resolve/messages.ftl
index 01f002c94..539b88aa9 100644
--- a/compiler/rustc_resolve/messages.ftl
+++ b/compiler/rustc_resolve/messages.ftl
@@ -1,79 +1,90 @@
-resolve_parent_module_reset_for_binding =
- parent module is reset for binding
+resolve_accessible_unsure = not sure whether the path is accessible or not
+ .note = the type may have associated items, but we are currently not checking them
+
+resolve_add_as_non_derive =
+ add as non-Derive macro
+ `#[{$macro_path}]`
resolve_ampersand_used_without_explicit_lifetime_name =
`&` without an explicit lifetime name cannot be used here
.note = explicit lifetime name needed here
-resolve_underscore_lifetime_name_cannot_be_used_here =
- `'_` cannot be used here
- .note = `'_` is a reserved lifetime name
+resolve_ancestor_only =
+ visibilities can only be restricted to ancestor modules
-resolve_crate_may_not_be_imported =
- `$crate` may not be imported
+resolve_associated_const_with_similar_name_exists =
+ there is an associated constant with a similar name
-resolve_crate_root_imports_must_be_named_explicitly =
- crate root imports need to be explicitly named: `use crate as name;`
+resolve_associated_fn_with_similar_name_exists =
+ there is an associated function with a similar name
-resolve_generic_params_from_outer_function =
- can't use generic parameters from outer function
- .label = use of generic parameter from outer function
- .suggestion = try using a local generic parameter instead
+resolve_associated_type_with_similar_name_exists =
+ there is an associated type with a similar name
-resolve_self_type_implicitly_declared_by_impl =
- `Self` type implicitly declared here, by this `impl`
+resolve_attempt_to_use_non_constant_value_in_constant =
+ attempt to use a non-constant value in a constant
+
+resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion =
+ non-constant value
+
+resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
+ consider using `{$suggestion}` instead of `{$current}`
+
+resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
+ this would need to be a `{$suggestion}`
+
+resolve_binding_shadows_something_unacceptable =
+ {$shadowing_binding}s cannot shadow {$shadowed_binding}s
+ .label = cannot be named the same as {$article} {$shadowed_binding}
+ .label_shadowed_binding = the {$shadowed_binding} `{$name}` is {$participle} here
+
+resolve_binding_shadows_something_unacceptable_suggestion =
+ try specify the pattern arguments
+
+resolve_cannot_capture_dynamic_environment_in_fn_item =
+ can't capture dynamic environment in a fn item
+ .help = use the `|| {"{"} ... {"}"}` closure form instead
resolve_cannot_use_self_type_here =
can't use `Self` here
-resolve_use_a_type_here_instead =
- use a type here instead
-
-resolve_type_param_from_outer_fn =
- type parameter from outer function
+resolve_const_not_member_of_trait =
+ const `{$const_}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
resolve_const_param_from_outer_fn =
const parameter from outer function
-resolve_try_using_local_generic_parameter =
- try using a local generic parameter instead
-
-resolve_try_adding_local_generic_param_on_method =
- try adding a local generic parameter in this method instead
-
-resolve_help_try_using_local_generic_param =
- try using a local generic parameter instead
+resolve_const_param_in_enum_discriminant =
+ const parameters may not be used in enum discriminant values
-resolve_name_is_already_used_as_generic_parameter =
- the name `{$name}` is already used for a generic parameter in this item's generic parameters
- .label = already used
- .first_use_of_name = first use of `{$name}`
+resolve_const_param_in_non_trivial_anon_const =
+ const parameters may only be used as standalone arguments, i.e. `{$name}`
-resolve_method_not_member_of_trait =
- method `{$method}` is not a member of trait `{$trait_}`
- .label = not a member of trait `{$trait_}`
+resolve_const_param_in_ty_of_const_param =
+ const parameters may not be used in the type of const parameters
-resolve_associated_fn_with_similar_name_exists =
- there is an associated function with a similar name
+resolve_crate_may_not_be_imported =
+ `$crate` may not be imported
-resolve_type_not_member_of_trait =
- type `{$type_}` is not a member of trait `{$trait_}`
- .label = not a member of trait `{$trait_}`
+resolve_crate_root_imports_must_be_named_explicitly =
+ crate root imports need to be explicitly named: `use crate as name;`
-resolve_associated_type_with_similar_name_exists =
- there is an associated type with a similar name
+resolve_expected_found =
+ expected module, found {$res} `{$path_str}`
+ .label = not a module
-resolve_const_not_member_of_trait =
- const `{$const_}` is not a member of trait `{$trait_}`
- .label = not a member of trait `{$trait_}`
+resolve_forward_declared_generic_param =
+ generic parameters with a default cannot use forward declared identifiers
+ .label = defaulted generic parameters cannot be forward declared
-resolve_associated_const_with_similar_name_exists =
- there is an associated constant with a similar name
+resolve_generic_params_from_outer_function =
+ can't use generic parameters from outer function
+ .label = use of generic parameter from outer function
+ .suggestion = try using a local generic parameter instead
-resolve_variable_bound_with_different_mode =
- variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
- .label = bound in different ways
- .first_binding_span = first binding
+resolve_help_try_using_local_generic_param =
+ try using a local generic parameter instead
resolve_ident_bound_more_than_once_in_parameter_list =
identifier `{$identifier}` is bound more than once in this parameter list
@@ -83,109 +94,104 @@ resolve_ident_bound_more_than_once_in_same_pattern =
identifier `{$identifier}` is bound more than once in the same pattern
.label = used in a pattern more than once
-resolve_undeclared_label =
- use of undeclared label `{$name}`
- .label = undeclared label `{$name}`
+resolve_imported_crate = `$crate` may not be imported
-resolve_label_with_similar_name_reachable =
- a label with a similar name is reachable
+resolve_indeterminate =
+ cannot determine resolution for the visibility
-resolve_try_using_similarly_named_label =
- try using similarly named label
+resolve_invalid_asm_sym =
+ invalid `sym` operand
+ .label = is a local variable
+ .help = `sym` operands must refer to either a function or a static
-resolve_unreachable_label_with_similar_name_exists =
- a label with a similar name exists but is unreachable
+resolve_label_with_similar_name_reachable =
+ a label with a similar name is reachable
-resolve_self_import_can_only_appear_once_in_the_list =
- `self` import can only appear once in an import list
- .label = can only appear once in an import list
+resolve_lifetime_param_in_enum_discriminant =
+ lifetime parameters may not be used in enum discriminant values
-resolve_self_import_only_in_import_list_with_non_empty_prefix =
- `self` import can only appear in an import list with a non-empty prefix
- .label = can only appear in an import list with a non-empty prefix
+resolve_lifetime_param_in_non_trivial_anon_const =
+ lifetime parameters may not be used in const expressions
-resolve_cannot_capture_dynamic_environment_in_fn_item =
- can't capture dynamic environment in a fn item
- .help = use the `|| {"{"} ... {"}"}` closure form instead
+resolve_lifetime_param_in_ty_of_const_param =
+ lifetime parameters may not be used in the type of const parameters
-resolve_attempt_to_use_non_constant_value_in_constant =
+resolve_lowercase_self =
attempt to use a non-constant value in a constant
+ .suggestion = try using `Self`
-resolve_attempt_to_use_non_constant_value_in_constant_with_suggestion =
- consider using `{$suggestion}` instead of `{$current}`
-
-resolve_attempt_to_use_non_constant_value_in_constant_label_with_suggestion =
- non-constant value
+resolve_macro_expected_found =
+ expected {$expected}, found {$found} `{$macro_path}`
-resolve_attempt_to_use_non_constant_value_in_constant_without_suggestion =
- this would need to be a `{$suggestion}`
+resolve_macro_use_extern_crate_self = `#[macro_use]` is not supported on `extern crate self`
-resolve_self_imports_only_allowed_within =
- `self` imports are only allowed within a {"{"} {"}"} list
+resolve_method_not_member_of_trait =
+ method `{$method}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
-resolve_self_imports_only_allowed_within_suggestion =
- consider importing the module directly
+resolve_module_only =
+ visibility must resolve to a module
-resolve_self_imports_only_allowed_within_multipart_suggestion =
- alternatively, use the multi-path `use` syntax to import `self`
+resolve_name_is_already_used_as_generic_parameter =
+ the name `{$name}` is already used for a generic parameter in this item's generic parameters
+ .label = already used
+ .first_use_of_name = first use of `{$name}`
-resolve_binding_shadows_something_unacceptable =
- {$shadowing_binding}s cannot shadow {$shadowed_binding}s
- .label = cannot be named the same as {$article} {$shadowed_binding}
- .label_shadowed_binding = the {$shadowed_binding} `{$name}` is {$participle} here
+resolve_param_in_enum_discriminant =
+ generic parameters may not be used in enum discriminant values
+ .label = cannot perform const operation using `{$name}`
-resolve_binding_shadows_something_unacceptable_suggestion =
- try specify the pattern arguments
+resolve_param_in_non_trivial_anon_const =
+ generic parameters may not be used in const operations
+ .label = cannot perform const operation using `{$name}`
-resolve_forward_declared_generic_param =
- generic parameters with a default cannot use forward declared identifiers
- .label = defaulted generic parameters cannot be forward declared
+resolve_param_in_non_trivial_anon_const_help =
+ use `#![feature(generic_const_exprs)]` to allow generic const expressions
resolve_param_in_ty_of_const_param =
the type of const parameters must not depend on other generic parameters
.label = the type must not depend on the parameter `{$name}`
-resolve_self_in_generic_param_default =
- generic parameters cannot use `Self` in their defaults
- .label = `Self` in generic parameter default
+resolve_parent_module_reset_for_binding =
+ parent module is reset for binding
-resolve_param_in_non_trivial_anon_const =
- generic parameters may not be used in const operations
- .label = cannot perform const operation using `{$name}`
+resolve_proc_macro_same_crate = can't use a procedural macro from the same crate that defines it
+ .help = you can define integration tests in a directory named `tests`
-resolve_param_in_non_trivial_anon_const_help =
- use `#![feature(generic_const_exprs)]` to allow generic const expressions
+resolve_relative_2018 =
+ relative paths are not supported in visibilities in 2018 edition or later
+ .suggestion = try
-resolve_param_in_non_trivial_anon_const_sub_type =
- type parameters may not be used in const expressions
+resolve_remove_surrounding_derive =
+ remove from the surrounding `derive()`
-resolve_param_in_non_trivial_anon_const_sub_non_type =
- const parameters may only be used as standalone arguments, i.e. `{$name}`
+resolve_self_import_can_only_appear_once_in_the_list =
+ `self` import can only appear once in an import list
+ .label = can only appear once in an import list
-resolve_unreachable_label =
- use of unreachable label `{$name}`
- .label = unreachable label `{$name}`
- .label_definition_span = unreachable label defined here
- .note = labels are unreachable through functions, closures, async blocks and modules
+resolve_self_import_only_in_import_list_with_non_empty_prefix =
+ `self` import can only appear in an import list with a non-empty prefix
+ .label = can only appear in an import list with a non-empty prefix
-resolve_unreachable_label_suggestion_use_similarly_named =
- try using similarly named label
+resolve_self_imports_only_allowed_within =
+ `self` imports are only allowed within a {"{"} {"}"} list
-resolve_unreachable_label_similar_name_reachable =
- a label with a similar name is reachable
+resolve_self_imports_only_allowed_within_multipart_suggestion =
+ alternatively, use the multi-path `use` syntax to import `self`
-resolve_unreachable_label_similar_name_unreachable =
- a label with a similar name exists but is also unreachable
+resolve_self_imports_only_allowed_within_suggestion =
+ consider importing the module directly
-resolve_trait_impl_mismatch =
- item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
- .label = does not match trait
- .label_trait_item = item in trait
+resolve_self_in_generic_param_default =
+ generic parameters cannot use `Self` in their defaults
+ .label = `Self` in generic parameter default
-resolve_invalid_asm_sym =
- invalid `sym` operand
- .label = is a local variable
- .help = `sym` operands must refer to either a function or a static
+resolve_self_type_implicitly_declared_by_impl =
+ `Self` type implicitly declared here, by this `impl`
+
+resolve_tool_module_imported =
+ cannot use a tool module through an import
+ .note = the tool module imported here
resolve_trait_impl_duplicate =
duplicate definitions with name `{$name}`:
@@ -193,33 +199,66 @@ resolve_trait_impl_duplicate =
.old_span_label = previous definition here
.trait_item_span = item in trait
-resolve_relative_2018 =
- relative paths are not supported in visibilities in 2018 edition or later
- .suggestion = try
+resolve_trait_impl_mismatch =
+ item `{$name}` is an associated {$kind}, which doesn't match its trait `{$trait_path}`
+ .label = does not match trait
+ .label_trait_item = item in trait
-resolve_ancestor_only =
- visibilities can only be restricted to ancestor modules
+resolve_try_adding_local_generic_param_on_method =
+ try adding a local generic parameter in this method instead
-resolve_expected_found =
- expected module, found {$res} `{$path_str}`
- .label = not a module
+resolve_try_using_local_generic_parameter =
+ try using a local generic parameter instead
-resolve_indeterminate =
- cannot determine resolution for the visibility
+resolve_try_using_similarly_named_label =
+ try using similarly named label
-resolve_tool_module_imported =
- cannot use a tool module through an import
- .note = the tool module imported here
+resolve_type_not_member_of_trait =
+ type `{$type_}` is not a member of trait `{$trait_}`
+ .label = not a member of trait `{$trait_}`
-resolve_module_only =
- visibility must resolve to a module
+resolve_type_param_from_outer_fn =
+ type parameter from outer function
-resolve_macro_expected_found =
- expected {$expected}, found {$found} `{$macro_path}`
+resolve_type_param_in_enum_discriminant =
+ type parameters may not be used in enum discriminant values
-resolve_remove_surrounding_derive =
- remove from the surrounding `derive()`
+resolve_type_param_in_non_trivial_anon_const =
+ type parameters may not be used in const expressions
-resolve_add_as_non_derive =
- add as non-Derive macro
- `#[{$macro_path}]`
+resolve_type_param_in_ty_of_const_param =
+ type parameters may not be used in the type of const parameters
+
+resolve_undeclared_label =
+ use of undeclared label `{$name}`
+ .label = undeclared label `{$name}`
+
+resolve_underscore_lifetime_name_cannot_be_used_here =
+ `'_` cannot be used here
+ .note = `'_` is a reserved lifetime name
+
+resolve_unreachable_label =
+ use of unreachable label `{$name}`
+ .label = unreachable label `{$name}`
+ .label_definition_span = unreachable label defined here
+ .note = labels are unreachable through functions, closures, async blocks and modules
+
+resolve_unreachable_label_similar_name_reachable =
+ a label with a similar name is reachable
+
+resolve_unreachable_label_similar_name_unreachable =
+ a label with a similar name exists but is also unreachable
+
+resolve_unreachable_label_suggestion_use_similarly_named =
+ try using similarly named label
+
+resolve_unreachable_label_with_similar_name_exists =
+ a label with a similar name exists but is unreachable
+
+resolve_use_a_type_here_instead =
+ use a type here instead
+
+resolve_variable_bound_with_different_mode =
+ variable `{$variable_name}` is bound inconsistently across alternatives separated by `|`
+ .label = bound in different ways
+ .first_binding_span = first binding
diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs
index ff0f1f559..727777333 100644
--- a/compiler/rustc_resolve/src/build_reduced_graph.rs
+++ b/compiler/rustc_resolve/src/build_reduced_graph.rs
@@ -9,10 +9,9 @@ use crate::def_collector::collect_definitions;
use crate::imports::{Import, ImportKind};
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
+use crate::{errors, BindingKey, MacroData};
use crate::{Determinacy, ExternPreludeEntry, Finalize, Module, ModuleKind, ModuleOrUniformRoot};
-use crate::{
- MacroData, NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError,
-};
+use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PerNS, ResolutionError};
use crate::{Resolver, ResolverArenas, Segment, ToNameBinding, VisResolutionError};
use rustc_ast::visit::{self, AssocCtxt, Visitor};
@@ -70,7 +69,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
T: ToNameBinding<'a>,
{
let binding = def.to_name_binding(self.arenas);
- let key = self.new_key(ident, ns);
+ let key = self.new_disambiguated_key(ident, ns);
if let Err(old_binding) = self.try_define(parent, key, binding) {
self.report_conflict(parent, ident, ns, old_binding, &binding);
}
@@ -130,7 +129,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
expn_id,
self.def_span(def_id),
// FIXME: Account for `#[no_implicit_prelude]` attributes.
- parent.map_or(false, |module| module.no_implicit_prelude),
+ parent.is_some_and(|module| module.no_implicit_prelude),
));
}
}
@@ -197,10 +196,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
pub(crate) fn build_reduced_graph_external(&mut self, module: Module<'a>) {
- // Query `module_children` is not used because hashing spans in its result is expensive.
- let children =
- Vec::from_iter(self.cstore().module_children_untracked(module.def_id(), self.tcx.sess));
- for child in children {
+ for child in self.tcx.module_children(module.def_id()) {
let parent_scope = ParentScope::module(module, self);
BuildReducedGraphVisitor { r: self, parent_scope }
.build_reduced_graph_for_external_crate_res(child);
@@ -380,7 +376,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ImportKind::Single { target, type_ns_only, .. } => {
self.r.per_ns(|this, ns| {
if !type_ns_only || ns == TypeNS {
- let key = this.new_key(target, ns);
+ let key = BindingKey::new(target, ns);
let mut resolution = this.resolution(current_module, key).borrow_mut();
resolution.add_single_import(import);
}
@@ -526,11 +522,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
ident.name = crate_name;
}
- self.r
- .tcx
- .sess
- .struct_span_err(item.span, "`$crate` may not be imported")
- .emit();
+ self.r.tcx.sess.emit_err(errors::CrateImported { span: item.span });
}
}
@@ -881,6 +873,11 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let msg = "macro-expanded `extern crate` items cannot \
shadow names passed with `--extern`";
self.r.tcx.sess.span_err(item.span, msg);
+ // `return` is intended to discard this binding because it's an
+ // unregistered ambiguity error which would result in a panic
+ // caused by inconsistency `path_res`
+ // more details: https://github.com/rust-lang/rust/pull/111761
+ return;
}
}
let entry = self.r.extern_prelude.entry(ident.normalize_to_macros_2_0()).or_insert(
@@ -929,9 +926,15 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
}
/// Builds the reduced graph for a single item in an external crate.
- fn build_reduced_graph_for_external_crate_res(&mut self, child: ModChild) {
+ fn build_reduced_graph_for_external_crate_res(&mut self, child: &ModChild) {
let parent = self.parent_scope.module;
- let ModChild { ident, res, vis, span, .. } = child;
+ let ModChild { ident, res, vis, ref reexport_chain } = *child;
+ let span = self.r.def_span(
+ reexport_chain
+ .first()
+ .and_then(|reexport| reexport.id())
+ .unwrap_or_else(|| res.def_id()),
+ );
let res = res.expect_non_local();
let expansion = self.parent_scope.expansion;
// Record primary definitions.
@@ -1001,7 +1004,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
let msg = format!("`{}` is already in scope", name);
let note =
"macro-expanded `#[macro_use]`s may not shadow existing macros (see RFC 1560)";
- self.r.tcx.sess.struct_span_err(span, &msg).note(note).emit();
+ self.r.tcx.sess.struct_span_err(span, msg).note(note).emit();
}
}
@@ -1025,11 +1028,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
self.r
.tcx
.sess
- .struct_span_err(
- attr.span,
- "`#[macro_use]` is not supported on `extern crate self`",
- )
- .emit();
+ .emit_err(errors::MacroUseExternCrateSelf { span: attr.span });
}
}
let ill_formed = |span| {
diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs
index ae3fd0ede..dc35c8b17 100644
--- a/compiler/rustc_resolve/src/check_unused.rs
+++ b/compiler/rustc_resolve/src/check_unused.rs
@@ -117,16 +117,11 @@ impl<'a, 'b, 'tcx> UnusedImportCheckVisitor<'a, 'b, 'tcx> {
match item.kind {
ast::UseTreeKind::Simple(Some(ident)) => {
if ident.name == kw::Underscore
- && !self
- .r
- .import_res_map
- .get(&id)
- .map(|per_ns| {
- per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
- matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
- })
+ && !self.r.import_res_map.get(&id).is_some_and(|per_ns| {
+ per_ns.iter().filter_map(|res| res.as_ref()).any(|res| {
+ matches!(res, Res::Def(DefKind::Trait | DefKind::TraitAlias, _))
})
- .unwrap_or(false)
+ })
{
self.unused_import(self.base_id).add(id);
}
@@ -418,7 +413,7 @@ impl Resolver<'_, '_> {
UNUSED_IMPORTS,
unused.use_tree_id,
ms,
- &msg,
+ msg,
BuiltinLintDiagnostics::UnusedImports(fix_msg.into(), fixes, test_module_span),
);
}
@@ -469,7 +464,7 @@ impl Resolver<'_, '_> {
.r
.extern_prelude
.get(&extern_crate.ident)
- .map_or(false, |entry| !entry.introduced_by_item)
+ .is_some_and(|entry| !entry.introduced_by_item)
{
continue;
}
diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs
index 0c9d30608..8c6ac822a 100644
--- a/compiler/rustc_resolve/src/diagnostics.rs
+++ b/compiler/rustc_resolve/src/diagnostics.rs
@@ -28,10 +28,10 @@ use rustc_span::symbol::{kw, sym, Ident, Symbol};
use rustc_span::{BytePos, Span, SyntaxContext};
use thin_vec::ThinVec;
-use crate::errors as errs;
use crate::imports::{Import, ImportKind};
use crate::late::{PatternSource, Rib};
use crate::path_names_to_string;
+use crate::{errors as errs, BindingKey};
use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, Finalize};
use crate::{HasGenericParams, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{LexicalScopeBinding, NameBinding, NameBindingKind, PrivacyError, VisResolutionError};
@@ -238,7 +238,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
},
};
- err.note(&format!(
+ err.note(format!(
"`{}` must be defined only once in the {} namespace of this {}",
name,
ns.descr(),
@@ -663,15 +663,17 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Ident::with_dummy_span(name),
Namespace::ValueNS,
&parent_scope,
- &|res: Res| match res {
- Res::Def(
- DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
- | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
- | DefKind::Const
- | DefKind::AssocConst,
- _,
- ) => true,
- _ => false,
+ &|res: Res| {
+ matches!(
+ res,
+ Res::Def(
+ DefKind::Ctor(CtorOf::Variant, CtorKind::Const)
+ | DefKind::Ctor(CtorOf::Struct, CtorKind::Const)
+ | DefKind::Const
+ | DefKind::AssocConst,
+ _,
+ )
+ )
},
);
@@ -681,7 +683,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
making the path in the pattern qualified: `path::to::ModOrType::{}`",
name,
);
- err.span_help(span, &help_msg);
+ err.span_help(span, help_msg);
}
show_candidates(
self.tcx,
@@ -781,10 +783,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some((suggestions, msg, applicability)) = suggestion {
if suggestions.is_empty() {
- err.help(&msg);
+ err.help(msg);
return err;
}
- err.multipart_suggestion(&msg, suggestions, applicability);
+ err.multipart_suggestion(msg, suggestions, applicability);
}
err
@@ -862,18 +864,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ResolutionError::ForwardDeclaredGenericParam => {
self.tcx.sess.create_err(errs::ForwardDeclaredGenericParam { span })
}
- ResolutionError::ParamInTyOfConstParam(name) => {
- self.tcx.sess.create_err(errs::ParamInTyOfConstParam { span, name })
- }
- ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => {
+ ResolutionError::ParamInTyOfConstParam { name, param_kind: is_type } => self
+ .tcx
+ .sess
+ .create_err(errs::ParamInTyOfConstParam { span, name, param_kind: is_type }),
+ ResolutionError::ParamInNonTrivialAnonConst { name, param_kind: is_type } => {
self.tcx.sess.create_err(errs::ParamInNonTrivialAnonConst {
span,
name,
- sub_is_type: if is_type {
- errs::ParamInNonTrivialAnonConstIsType::AType
- } else {
- errs::ParamInNonTrivialAnonConstIsType::NotAType { name }
- },
+ param_kind: is_type,
help: self
.tcx
.sess
@@ -881,6 +880,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.then_some(errs::ParamInNonTrivialAnonConstHelp),
})
}
+ ResolutionError::ParamInEnumDiscriminant { name, param_kind: is_type } => self
+ .tcx
+ .sess
+ .create_err(errs::ParamInEnumDiscriminant { span, name, param_kind: is_type }),
ResolutionError::SelfInGenericParamDefault => {
self.tcx.sess.create_err(errs::SelfInGenericParamDefault { span })
}
@@ -928,7 +931,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
} => {
let mut err = self.tcx.sess.struct_span_err_with_code(
span,
- &format!(
+ format!(
"item `{}` is an associated {}, which doesn't match its trait `{}`",
name, kind, trait_path,
),
@@ -945,6 +948,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ResolutionError::InvalidAsmSym => {
self.tcx.sess.create_err(errs::InvalidAsmSym { span })
}
+ ResolutionError::LowercaseSelf => {
+ self.tcx.sess.create_err(errs::LowercaseSelf { span })
+ }
}
}
@@ -1357,7 +1363,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if macro_kind == MacroKind::Derive && (ident.name == sym::Send || ident.name == sym::Sync) {
let msg = format!("unsafe traits like `{}` should be implemented explicitly", ident);
- err.span_note(ident.span, &msg);
+ err.span_note(ident.span, msg);
return;
}
if self.macro_names.contains(&ident.normalize_to_macros_2_0()) {
@@ -1417,7 +1423,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if !import.span.is_dummy() {
err.span_note(
import.span,
- &format!("`{}` is imported here, but it is {}", ident, desc),
+ format!("`{}` is imported here, but it is {}", ident, desc),
);
// Silence the 'unused import' warning we might get,
// since this diagnostic already covers that import.
@@ -1425,7 +1431,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
return;
}
}
- err.note(&format!("`{}` is in scope, but it is {}", ident, desc));
+ err.note(format!("`{}` is in scope, but it is {}", ident, desc));
return;
}
}
@@ -1472,7 +1478,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
err.span_label(
self.tcx.sess.source_map().guess_head_span(def_span),
- &format!(
+ format!(
"{}{} `{}` defined here",
prefix,
suggestion.res.descr(),
@@ -1490,7 +1496,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
format!("maybe you meant this {}", suggestion.res.descr())
}
};
- err.span_suggestion(span, &msg, suggestion.candidate, Applicability::MaybeIncorrect);
+ err.span_suggestion(span, msg, suggestion.candidate, Applicability::MaybeIncorrect);
true
}
@@ -1532,7 +1538,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut err = struct_span_err!(self.tcx.sess, ident.span, E0659, "`{ident}` is ambiguous");
err.span_label(ident.span, "ambiguous name");
- err.note(&format!("ambiguous because of {}", kind.descr()));
+ err.note(format!("ambiguous because of {}", kind.descr()));
let mut could_refer_to = |b: &NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
@@ -1560,10 +1566,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
AmbiguityErrorMisc::FromPrelude | AmbiguityErrorMisc::None => {}
}
- err.span_note(b.span, &note_msg);
+ err.span_note(b.span, note_msg);
for (i, help_msg) in help_msgs.iter().enumerate() {
let or = if i == 0 { "" } else { "or " };
- err.help(&format!("{}{}", or, help_msg));
+ err.help(format!("{}{}", or, help_msg));
}
};
@@ -1606,7 +1612,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let descr = get_descr(binding);
let mut err =
struct_span_err!(self.tcx.sess, ident.span, E0603, "{} `{}` is private", descr, ident);
- err.span_label(ident.span, &format!("private {}", descr));
+ err.span_label(ident.span, format!("private {}", descr));
let mut non_exhaustive = None;
// If an ADT is foreign and marked as `non_exhaustive`, then that's
@@ -1621,7 +1627,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
err.span_label(span, "a constructor is private if any of the fields is private");
if let Res::Def(_, d) = res && let Some(fields) = self.field_visibility_spans.get(&d) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"consider making the field{} publicly accessible",
pluralize!(fields.len())
),
@@ -1674,7 +1680,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
format!("cannot be constructed because it is `#[non_exhaustive]`"),
);
}
- err.span_note(note_span, &msg);
+ err.span_note(note_span, msg);
}
err.emit();
@@ -1826,8 +1832,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
(msg, None)
} else if ident.name == kw::SelfUpper {
- ("`Self` is only available in impls, traits, and type definitions".to_string(), None)
- } else if ident.name.as_str().chars().next().map_or(false, |c| c.is_ascii_uppercase()) {
+ // As mentioned above, `opt_ns` being `None` indicates a module path in import.
+ // We can use this to improve a confusing error for, e.g. `use Self::Variant` in an
+ // impl
+ if opt_ns.is_none() {
+ ("`Self` cannot be used in imports".to_string(), None)
+ } else {
+ (
+ "`Self` is only available in impls, traits, and type definitions".to_string(),
+ None,
+ )
+ }
+ } else if ident.name.as_str().chars().next().is_some_and(|c| c.is_ascii_uppercase()) {
// Check whether the name refers to an item in the value namespace.
let binding = if let Some(ribs) = ribs {
self.resolve_ident_in_lexical_scope(
@@ -1867,15 +1883,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Some(LexicalScopeBinding::Item(name_binding)) => Some(name_binding.span),
_ => None,
};
- let suggestion = if let Some(span) = match_span {
- Some((
+ let suggestion = match_span.map(|span| {
+ (
vec![(span, String::from(""))],
format!("`{}` is defined here, but is not a type", ident),
Applicability::MaybeIncorrect,
- ))
- } else {
- None
- };
+ )
+ });
(format!("use of undeclared type `{}`", ident), suggestion)
} else {
@@ -2077,7 +2091,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
let resolutions = self.resolutions(crate_module).borrow();
- let resolution = resolutions.get(&self.new_key(ident, MacroNS))?;
+ let binding_key = BindingKey::new(ident, MacroNS);
+ let resolution = resolutions.get(&binding_key)?;
let binding = resolution.borrow().binding()?;
if let Res::Def(DefKind::Macro(MacroKind::Bang), _) = binding.res() {
let module_name = crate_module.kind.name().unwrap();
@@ -2150,7 +2165,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let is_definitely_crate = import
.module_path
.first()
- .map_or(false, |f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
+ .is_some_and(|f| f.ident.name != kw::SelfLower && f.ident.name != kw::Super);
// Add the import to the start, with a `{` if required.
let start_point = source_map.start_point(after_crate_name);
@@ -2444,7 +2459,7 @@ fn show_candidates(
};
for note in accessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
- err.note(note);
+ err.note(note.clone());
}
if let Some(span) = use_placement_span {
@@ -2452,7 +2467,7 @@ fn show_candidates(
DiagnosticMode::Pattern => {
err.span_suggestions(
span,
- &msg,
+ msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
);
@@ -2471,7 +2486,7 @@ fn show_candidates(
err.span_suggestions_with_style(
span,
- &msg,
+ msg,
accessible_path_strings.into_iter().map(|a| a.0),
Applicability::MaybeIncorrect,
SuggestionStyle::ShowAlways,
@@ -2481,7 +2496,7 @@ fn show_candidates(
if sp.can_be_used_for_suggestions() {
err.span_suggestion_verbose(
sp,
- &format!("if you import `{}`, refer to it directly", last.ident),
+ format!("if you import `{}`, refer to it directly", last.ident),
"",
Applicability::Unspecified,
);
@@ -2495,7 +2510,7 @@ fn show_candidates(
msg.push_str(&candidate.0);
}
- err.help(&msg);
+ err.help(msg);
}
} else if !matches!(mode, DiagnosticMode::Import) {
assert!(!inaccessible_path_strings.is_empty());
@@ -2520,9 +2535,9 @@ fn show_candidates(
let span = tcx.sess.source_map().guess_head_span(span);
let mut multi_span = MultiSpan::from_span(span);
multi_span.push_span_label(span, "not accessible");
- err.span_note(multi_span, &msg);
+ err.span_note(multi_span, msg);
} else {
- err.note(&msg);
+ err.note(msg);
}
if let Some(note) = (*note).as_deref() {
err.note(note);
@@ -2566,10 +2581,10 @@ fn show_candidates(
}
for note in inaccessible_path_strings.iter().flat_map(|cand| cand.3.as_ref()) {
- err.note(note);
+ err.note(note.clone());
}
- err.span_note(multi_span, &msg);
+ err.span_note(multi_span, msg);
}
}
}
diff --git a/compiler/rustc_resolve/src/effective_visibilities.rs b/compiler/rustc_resolve/src/effective_visibilities.rs
index bed579f6b..7393bdb38 100644
--- a/compiler/rustc_resolve/src/effective_visibilities.rs
+++ b/compiler/rustc_resolve/src/effective_visibilities.rs
@@ -175,7 +175,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
/// to not update anything and we can skip it.
///
/// We are checking this condition only if the correct value of private visibility is
- /// cheaply available, otherwise it does't make sense performance-wise.
+ /// cheaply available, otherwise it doesn't make sense performance-wise.
///
/// `None` is returned if the update can be skipped,
/// and cheap private visibility is returned otherwise.
@@ -199,7 +199,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
let tcx = self.r.tcx;
self.changed |= self.import_effective_visibilities.update(
binding,
- nominal_vis,
+ Some(nominal_vis),
|| cheap_private_vis.unwrap_or_else(|| self.r.private_vis_import(binding)),
inherited_eff_vis,
parent_id.level(),
@@ -213,7 +213,7 @@ impl<'r, 'a, 'tcx> EffectiveVisibilitiesVisitor<'r, 'a, 'tcx> {
let tcx = self.r.tcx;
self.changed |= self.def_effective_visibilities.update(
def_id,
- nominal_vis,
+ Some(nominal_vis),
|| cheap_private_vis.unwrap_or_else(|| self.r.private_vis_def(def_id)),
inherited_eff_vis,
parent_id.level(),
diff --git a/compiler/rustc_resolve/src/errors.rs b/compiler/rustc_resolve/src/errors.rs
index afa796cb6..2ab55f126 100644
--- a/compiler/rustc_resolve/src/errors.rs
+++ b/compiler/rustc_resolve/src/errors.rs
@@ -22,7 +22,7 @@ pub(crate) struct UnderscoreLifetimeNameCannotBeUsedHere(#[primary_span] pub(cra
#[derive(Diagnostic)]
#[diag(resolve_crate_may_not_be_imported)]
-pub(crate) struct CrateMayNotBeImprted(#[primary_span] pub(crate) Span);
+pub(crate) struct CrateMayNotBeImported(#[primary_span] pub(crate) Span);
#[derive(Diagnostic)]
#[diag(resolve_crate_root_imports_must_be_named_explicitly)]
@@ -326,6 +326,18 @@ pub(crate) struct ParamInTyOfConstParam {
#[label]
pub(crate) span: Span,
pub(crate) name: Symbol,
+ #[subdiagnostic]
+ pub(crate) param_kind: Option<ParamKindInTyOfConstParam>,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ParamKindInTyOfConstParam {
+ #[note(resolve_type_param_in_ty_of_const_param)]
+ Type,
+ #[note(resolve_const_param_in_ty_of_const_param)]
+ Const,
+ #[note(resolve_lifetime_param_in_ty_of_const_param)]
+ Lifetime,
}
#[derive(Diagnostic)]
@@ -344,7 +356,7 @@ pub(crate) struct ParamInNonTrivialAnonConst {
pub(crate) span: Span,
pub(crate) name: Symbol,
#[subdiagnostic]
- pub(crate) sub_is_type: ParamInNonTrivialAnonConstIsType,
+ pub(crate) param_kind: ParamKindInNonTrivialAnonConst,
#[subdiagnostic]
pub(crate) help: Option<ParamInNonTrivialAnonConstHelp>,
}
@@ -354,11 +366,13 @@ pub(crate) struct ParamInNonTrivialAnonConst {
pub(crate) struct ParamInNonTrivialAnonConstHelp;
#[derive(Subdiagnostic)]
-pub(crate) enum ParamInNonTrivialAnonConstIsType {
- #[note(resolve_param_in_non_trivial_anon_const_sub_type)]
- AType,
- #[help(resolve_param_in_non_trivial_anon_const_sub_non_type)]
- NotAType { name: Symbol },
+pub(crate) enum ParamKindInNonTrivialAnonConst {
+ #[note(resolve_type_param_in_non_trivial_anon_const)]
+ Type,
+ #[help(resolve_const_param_in_non_trivial_anon_const)]
+ Const { name: Symbol },
+ #[note(resolve_lifetime_param_in_non_trivial_anon_const)]
+ Lifetime,
}
#[derive(Diagnostic)]
@@ -429,6 +443,14 @@ pub(crate) struct InvalidAsmSym {
}
#[derive(Diagnostic)]
+#[diag(resolve_lowercase_self)]
+pub(crate) struct LowercaseSelf {
+ #[primary_span]
+ #[suggestion(code = "Self", applicability = "maybe-incorrect", style = "short")]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
#[diag(resolve_trait_impl_duplicate, code = "E0201")]
pub(crate) struct TraitImplDuplicate {
#[primary_span]
@@ -508,3 +530,55 @@ pub(crate) struct RemoveSurroundingDerive {
pub(crate) struct AddAsNonDerive<'a> {
pub(crate) macro_path: &'a str,
}
+
+#[derive(Diagnostic)]
+#[diag(resolve_proc_macro_same_crate)]
+pub(crate) struct ProcMacroSameCrate {
+ #[primary_span]
+ pub(crate) span: Span,
+ #[help]
+ pub(crate) is_test: bool,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_imported_crate)]
+pub(crate) struct CrateImported {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_macro_use_extern_crate_self)]
+pub(crate) struct MacroUseExternCrateSelf {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_accessible_unsure)]
+#[note]
+pub(crate) struct CfgAccessibleUnsure {
+ #[primary_span]
+ pub(crate) span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(resolve_param_in_enum_discriminant)]
+pub(crate) struct ParamInEnumDiscriminant {
+ #[primary_span]
+ #[label]
+ pub(crate) span: Span,
+ pub(crate) name: Symbol,
+ #[subdiagnostic]
+ pub(crate) param_kind: ParamKindInEnumDiscriminant,
+}
+
+#[derive(Subdiagnostic)]
+pub(crate) enum ParamKindInEnumDiscriminant {
+ #[note(resolve_type_param_in_enum_discriminant)]
+ Type,
+ #[note(resolve_const_param_in_enum_discriminant)]
+ Const,
+ #[note(resolve_lifetime_param_in_enum_discriminant)]
+ Lifetime,
+}
diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs
index 5a56d7b99..945c7ce3a 100644
--- a/compiler/rustc_resolve/src/ident.rs
+++ b/compiler/rustc_resolve/src/ident.rs
@@ -13,10 +13,12 @@ use rustc_span::{Span, DUMMY_SP};
use std::ptr;
+use crate::errors::{ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst};
use crate::late::{
- ConstantHasGenerics, ConstantItemKind, HasGenericParams, PathSource, Rib, RibKind,
+ ConstantHasGenerics, HasGenericParams, NoConstantGenericsReason, PathSource, Rib, RibKind,
};
use crate::macros::{sub_namespace_match, MacroRulesScope};
+use crate::BindingKey;
use crate::{errors, AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy, Finalize};
use crate::{Import, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot};
use crate::{NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res};
@@ -24,7 +26,6 @@ use crate::{ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding,
use Determinacy::*;
use Namespace::*;
-use RibKind::*;
type Visibility = ty::Visibility<LocalDefId>;
@@ -324,8 +325,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
module = match ribs[i].kind {
- ModuleRibKind(module) => module,
- MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
+ RibKind::Module(module) => module,
+ RibKind::MacroDefinition(def) if def == self.macro_def(ident.span.ctxt()) => {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
ident.span.remove_mark();
@@ -527,7 +528,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
lint_id,
orig_ident.span,
- &format!(
+ format!(
"cannot find {} `{}` in this scope",
ns.descr(),
ident
@@ -865,7 +866,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
};
- let key = self.new_key(ident, ns);
+ let key = BindingKey::new(ident, ns);
let resolution =
self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
@@ -1084,7 +1085,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let ribs = &all_ribs[rib_index + 1..];
// An invalid forward use of a generic parameter from a previous default.
- if let ForwardGenericParamBanRibKind = all_ribs[rib_index].kind {
+ if let RibKind::ForwardGenericParamBan = all_ribs[rib_index].kind {
if let Some(span) = finalize {
let res_error = if rib_ident.name == kw::SelfUpper {
ResolutionError::SelfInGenericParamDefault
@@ -1104,14 +1105,14 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
for rib in ribs {
match rib.kind {
- NormalRibKind
- | ClosureOrAsyncRibKind
- | ModuleRibKind(..)
- | MacroDefinition(..)
- | ForwardGenericParamBanRibKind => {
+ RibKind::Normal
+ | RibKind::ClosureOrAsync
+ | RibKind::Module(..)
+ | RibKind::MacroDefinition(..)
+ | RibKind::ForwardGenericParamBan => {
// Nothing to do. Continue.
}
- ItemRibKind(_) | AssocItemRibKind => {
+ RibKind::Item(_) | RibKind::AssocItem => {
// This was an attempt to access an upvar inside a
// named function item. This is not allowed, so we
// report an error.
@@ -1123,42 +1124,45 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
res_err = Some((span, CannotCaptureDynamicEnvironmentInFnItem));
}
}
- ConstantItemRibKind(_, item) => {
+ RibKind::ConstantItem(_, item) => {
// Still doesn't deal with upvars
if let Some(span) = finalize {
- let (span, resolution_error) =
- if let Some((ident, constant_item_kind)) = item {
- let kind_str = match constant_item_kind {
- ConstantItemKind::Const => "const",
- ConstantItemKind::Static => "static",
- };
- (
- span,
- AttemptToUseNonConstantValueInConstant(
- ident, "let", kind_str,
- ),
- )
- } else {
- (
- rib_ident.span,
- AttemptToUseNonConstantValueInConstant(
- original_rib_ident_def,
- "const",
- "let",
- ),
- )
- };
+ let (span, resolution_error) = match item {
+ None if rib_ident.as_str() == "self" => (span, LowercaseSelf),
+ None => (
+ rib_ident.span,
+ AttemptToUseNonConstantValueInConstant(
+ original_rib_ident_def,
+ "const",
+ "let",
+ ),
+ ),
+ Some((ident, kind)) => (
+ span,
+ AttemptToUseNonConstantValueInConstant(
+ ident,
+ "let",
+ kind.as_str(),
+ ),
+ ),
+ };
self.report_error(span, resolution_error);
}
return Res::Err;
}
- ConstParamTyRibKind => {
+ RibKind::ConstParamTy => {
if let Some(span) = finalize {
- self.report_error(span, ParamInTyOfConstParam(rib_ident.name));
+ self.report_error(
+ span,
+ ParamInTyOfConstParam {
+ name: rib_ident.name,
+ param_kind: None,
+ },
+ );
}
return Res::Err;
}
- InlineAsmSymRibKind => {
+ RibKind::InlineAsmSym => {
if let Some(span) = finalize {
self.report_error(span, InvalidAsmSym);
}
@@ -1174,23 +1178,19 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Res::Def(DefKind::TyParam, _) | Res::SelfTyParam { .. } | Res::SelfTyAlias { .. } => {
for rib in ribs {
let has_generic_params: HasGenericParams = match rib.kind {
- NormalRibKind
- | ClosureOrAsyncRibKind
- | ModuleRibKind(..)
- | MacroDefinition(..)
- | InlineAsmSymRibKind
- | AssocItemRibKind
- | ForwardGenericParamBanRibKind => {
+ RibKind::Normal
+ | RibKind::ClosureOrAsync
+ | RibKind::Module(..)
+ | RibKind::MacroDefinition(..)
+ | RibKind::InlineAsmSym
+ | RibKind::AssocItem
+ | RibKind::ForwardGenericParamBan => {
// Nothing to do. Continue.
continue;
}
- ConstantItemRibKind(trivial, _) => {
- let features = self.tcx.sess.features_untracked();
- // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !(trivial == ConstantHasGenerics::Yes
- || features.generic_const_exprs)
- {
+ RibKind::ConstantItem(trivial, _) => {
+ if let ConstantHasGenerics::No(cause) = trivial {
// HACK(min_const_generics): If we encounter `Self` in an anonymous
// constant we can't easily tell if it's generic at this stage, so
// we instead remember this and then enforce the self type to be
@@ -1208,13 +1208,22 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
} else {
if let Some(span) = finalize {
- self.report_error(
- span,
- ResolutionError::ParamInNonTrivialAnonConst {
- name: rib_ident.name,
- is_type: true,
- },
- );
+ let error = match cause {
+ NoConstantGenericsReason::IsEnumDiscriminant => {
+ ResolutionError::ParamInEnumDiscriminant {
+ name: rib_ident.name,
+ param_kind: ParamKindInEnumDiscriminant::Type,
+ }
+ }
+ NoConstantGenericsReason::NonTrivialConstArg => {
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ param_kind:
+ ParamKindInNonTrivialAnonConst::Type,
+ }
+ }
+ };
+ self.report_error(span, error);
self.tcx.sess.delay_span_bug(span, CG_BUG_STR);
}
@@ -1226,12 +1235,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
// This was an attempt to use a type parameter outside its scope.
- ItemRibKind(has_generic_params) => has_generic_params,
- ConstParamTyRibKind => {
+ RibKind::Item(has_generic_params) => has_generic_params,
+ RibKind::ConstParamTy => {
if let Some(span) = finalize {
self.report_error(
span,
- ResolutionError::ParamInTyOfConstParam(rib_ident.name),
+ ResolutionError::ParamInTyOfConstParam {
+ name: rib_ident.name,
+ param_kind: Some(errors::ParamKindInTyOfConstParam::Type),
+ },
);
}
return Res::Err;
@@ -1253,29 +1265,34 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Res::Def(DefKind::ConstParam, _) => {
for rib in ribs {
let has_generic_params = match rib.kind {
- NormalRibKind
- | ClosureOrAsyncRibKind
- | ModuleRibKind(..)
- | MacroDefinition(..)
- | InlineAsmSymRibKind
- | AssocItemRibKind
- | ForwardGenericParamBanRibKind => continue,
-
- ConstantItemRibKind(trivial, _) => {
- let features = self.tcx.sess.features_untracked();
- // HACK(min_const_generics): We currently only allow `N` or `{ N }`.
- if !(trivial == ConstantHasGenerics::Yes
- || features.generic_const_exprs)
- {
+ RibKind::Normal
+ | RibKind::ClosureOrAsync
+ | RibKind::Module(..)
+ | RibKind::MacroDefinition(..)
+ | RibKind::InlineAsmSym
+ | RibKind::AssocItem
+ | RibKind::ForwardGenericParamBan => continue,
+
+ RibKind::ConstantItem(trivial, _) => {
+ if let ConstantHasGenerics::No(cause) = trivial {
if let Some(span) = finalize {
- self.report_error(
- span,
- ResolutionError::ParamInNonTrivialAnonConst {
- name: rib_ident.name,
- is_type: false,
- },
- );
- self.tcx.sess.delay_span_bug(span, CG_BUG_STR);
+ let error = match cause {
+ NoConstantGenericsReason::IsEnumDiscriminant => {
+ ResolutionError::ParamInEnumDiscriminant {
+ name: rib_ident.name,
+ param_kind: ParamKindInEnumDiscriminant::Const,
+ }
+ }
+ NoConstantGenericsReason::NonTrivialConstArg => {
+ ResolutionError::ParamInNonTrivialAnonConst {
+ name: rib_ident.name,
+ param_kind: ParamKindInNonTrivialAnonConst::Const {
+ name: rib_ident.name,
+ },
+ }
+ }
+ };
+ self.report_error(span, error);
}
return Res::Err;
@@ -1284,12 +1301,15 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
continue;
}
- ItemRibKind(has_generic_params) => has_generic_params,
- ConstParamTyRibKind => {
+ RibKind::Item(has_generic_params) => has_generic_params,
+ RibKind::ConstParamTy => {
if let Some(span) = finalize {
self.report_error(
span,
- ResolutionError::ParamInTyOfConstParam(rib_ident.name),
+ ResolutionError::ParamInTyOfConstParam {
+ name: rib_ident.name,
+ param_kind: Some(errors::ParamKindInTyOfConstParam::Const),
+ },
);
}
return Res::Err;
@@ -1345,7 +1365,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
ribs: Option<&PerNS<Vec<Rib<'a>>>>,
ignore_binding: Option<&'a NameBinding<'a>>,
) -> PathResult<'a> {
- debug!("resolve_path(path={:?}, opt_ns={:?}, finalize={:?})", path, opt_ns, finalize);
+ debug!(
+ "resolve_path(path={:?}, opt_ns={:?}, finalize={:?}) path_len: {}",
+ path,
+ opt_ns,
+ finalize,
+ path.len()
+ );
let mut module = None;
let mut allow_super = true;
diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs
index 3c22d51c3..7c4c05d4b 100644
--- a/compiler/rustc_resolve/src/imports.rs
+++ b/compiler/rustc_resolve/src/imports.rs
@@ -405,17 +405,18 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
t
}
- // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed resolution,
- // also mark such failed imports as used to avoid duplicate diagnostics.
- fn import_dummy_binding(&mut self, import: &'a Import<'a>) {
+ // Define a dummy resolution containing a `Res::Err` as a placeholder for a failed
+ // or indeterminate resolution, also mark such failed imports as used to avoid duplicate diagnostics.
+ fn import_dummy_binding(&mut self, import: &'a Import<'a>, is_indeterminate: bool) {
if let ImportKind::Single { target, ref target_bindings, .. } = import.kind {
- if target_bindings.iter().any(|binding| binding.get().is_some()) {
+ if !(is_indeterminate || target_bindings.iter().all(|binding| binding.get().is_none()))
+ {
return; // Has resolution, do not create the dummy binding
}
let dummy_binding = self.dummy_binding;
let dummy_binding = self.import(dummy_binding, import);
self.per_ns(|this, ns| {
- let key = this.new_key(target, ns);
+ let key = BindingKey::new(target, ns);
let _ = this.try_define(import.parent_scope.module, key, dummy_binding);
});
self.record_use(target, dummy_binding, false);
@@ -474,7 +475,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
// If this import is unresolved then create a dummy import
// resolution for it so that later resolve stages won't complain.
- self.import_dummy_binding(import);
+ self.import_dummy_binding(import, is_indeterminate);
if let Some(err) = unresolved_import_error {
if let ImportKind::Single { source, ref source_bindings, .. } = import.kind {
@@ -578,7 +579,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let mut diag = struct_span_err!(self.tcx.sess, span, E0432, "{}", &msg);
if let Some((_, UnresolvedImportError { note: Some(note), .. })) = errors.iter().last() {
- diag.note(note);
+ diag.note(note.clone());
}
for (import, err) in errors.into_iter().take(MAX_LABEL_COUNT) {
@@ -588,10 +589,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some((suggestions, msg, applicability)) = err.suggestion {
if suggestions.is_empty() {
- diag.help(&msg);
+ diag.help(msg);
continue;
}
- diag.multipart_suggestion(&msg, suggestions, applicability);
+ diag.multipart_suggestion(msg, suggestions, applicability);
}
if let Some(candidates) = &err.candidates {
@@ -712,7 +713,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
.span_label(import.span, "cannot be imported directly")
.emit();
}
- let key = this.new_key(target, ns);
+ let key = BindingKey::new(target, ns);
this.update_resolution(parent, key, |_, resolution| {
resolution.single_imports.remove(&Interned::new_unchecked(import));
});
@@ -1063,7 +1064,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
PUB_USE_OF_PRIVATE_EXTERN_CRATE,
import_id,
import.span,
- &msg,
+ msg,
);
} else {
let error_msg = if crate_private_reexport {
@@ -1084,7 +1085,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
struct_span_err!(self.tcx.sess, import.span, E0365, "{}", error_msg)
.span_label(import.span, label_msg)
- .note(&format!("consider declaring type or module `{}` with `pub`", ident))
+ .note(format!("consider declaring type or module `{}` with `pub`", ident))
.emit();
} else {
let mut err =
@@ -1102,7 +1103,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
_ => {
err.span_note(
import.span,
- &format!(
+ format!(
"consider marking `{ident}` as `pub` in the imported module"
),
);
@@ -1200,7 +1201,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
UNUSED_IMPORTS,
id,
import.span,
- &format!("the item `{}` is imported redundantly", ident),
+ format!("the item `{}` is imported redundantly", ident),
BuiltinLintDiagnostics::RedundantImport(redundant_spans, ident),
);
}
@@ -1261,14 +1262,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
*module.globs.borrow_mut() = Vec::new();
if let Some(def_id) = module.opt_def_id() {
- let mut non_reexports = Vec::new();
- let mut reexports = Vec::new();
+ let mut children = Vec::new();
module.for_each_child(self, |this, ident, _, binding| {
let res = binding.res().expect_non_local();
- if !binding.is_import() {
- non_reexports.push(res.def_id().expect_local());
- } else if res != def::Res::Err && !binding.is_ambiguity() {
+ if res != def::Res::Err && !binding.is_ambiguity() {
let mut reexport_chain = SmallVec::new();
let mut next_binding = binding;
while let NameBindingKind::Import { binding, import, .. } = next_binding.kind {
@@ -1276,23 +1274,13 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
next_binding = binding;
}
- reexports.push(ModChild {
- ident,
- res,
- vis: binding.vis,
- span: binding.span,
- reexport_chain,
- });
+ children.push(ModChild { ident, res, vis: binding.vis, reexport_chain });
}
});
- // Should be fine because this code is only called for local modules.
- let def_id = def_id.expect_local();
- if !non_reexports.is_empty() {
- self.module_children_non_reexports.insert(def_id, non_reexports);
- }
- if !reexports.is_empty() {
- self.module_children_reexports.insert(def_id, reexports);
+ if !children.is_empty() {
+ // Should be fine because this code is only called for local modules.
+ self.module_children.insert(def_id.expect_local(), children);
}
}
}
diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs
index 90a2fa89c..e06119076 100644
--- a/compiler/rustc_resolve/src/late.rs
+++ b/compiler/rustc_resolve/src/late.rs
@@ -6,8 +6,7 @@
//! If you wonder why there's no `early.rs`, that's because it's split into three files -
//! `build_reduced_graph.rs`, `macros.rs` and `imports.rs`.
-use RibKind::*;
-
+use crate::BindingKey;
use crate::{path_names_to_string, rustdoc, BindingError, Finalize, LexicalScopeBinding};
use crate::{Module, ModuleOrUniformRoot, NameBinding, ParentScope, PathResult};
use crate::{ResolutionError, Resolver, Segment, UseError};
@@ -18,7 +17,7 @@ use rustc_ast::*;
use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap};
use rustc_errors::{Applicability, DiagnosticArgValue, DiagnosticId, IntoDiagnosticArg};
use rustc_hir::def::Namespace::{self, *};
-use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, PartialRes, PerNS};
+use rustc_hir::def::{self, CtorKind, DefKind, LifetimeRes, NonMacroAttrKind, PartialRes, PerNS};
use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::{BindingAnnotation, PrimTy, TraitCandidate};
use rustc_middle::middle::resolve_bound_vars::Set1;
@@ -68,6 +67,15 @@ enum IsRepeatExpr {
Yes,
}
+/// Describes whether an `AnonConst` is a type level const arg or
+/// some other form of anon const (i.e. inline consts or enum discriminants)
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum AnonConstKind {
+ EnumDiscriminant,
+ InlineConst,
+ ConstArg(IsRepeatExpr),
+}
+
impl PatternSource {
fn descr(self) -> &'static str {
match self {
@@ -107,7 +115,7 @@ pub(crate) enum HasGenericParams {
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantHasGenerics {
Yes,
- No,
+ No(NoConstantGenericsReason),
}
impl ConstantHasGenerics {
@@ -116,12 +124,42 @@ impl ConstantHasGenerics {
}
}
+/// Reason for why an anon const is not allowed to reference generic parameters
+#[derive(Copy, Clone, Debug, Eq, PartialEq)]
+pub(crate) enum NoConstantGenericsReason {
+ /// Const arguments are only allowed to use generic parameters when:
+ /// - `feature(generic_const_exprs)` is enabled
+ /// or
+ /// - the const argument is a sole const generic paramater, i.e. `foo::<{ N }>()`
+ ///
+ /// If neither of the above are true then this is used as the cause.
+ NonTrivialConstArg,
+ /// Enum discriminants are not allowed to reference generic parameters ever, this
+ /// is used when an anon const is in the following position:
+ ///
+ /// ```rust,compile_fail
+ /// enum Foo<const N: isize> {
+ /// Variant = { N }, // this anon const is not allowed to use generics
+ /// }
+ /// ```
+ IsEnumDiscriminant,
+}
+
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
pub(crate) enum ConstantItemKind {
Const,
Static,
}
+impl ConstantItemKind {
+ pub(crate) fn as_str(&self) -> &'static str {
+ match self {
+ Self::Const => "const",
+ Self::Static => "static",
+ }
+ }
+}
+
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
enum RecordPartialRes {
Yes,
@@ -133,28 +171,28 @@ enum RecordPartialRes {
#[derive(Copy, Clone, Debug)]
pub(crate) enum RibKind<'a> {
/// No restriction needs to be applied.
- NormalRibKind,
+ Normal,
/// We passed through an impl or trait and are now in one of its
/// methods or associated types. Allow references to ty params that impl or trait
/// binds. Disallow any other upvars (including other ty params that are
/// upvars).
- AssocItemRibKind,
+ AssocItem,
/// We passed through a closure. Disallow labels.
- ClosureOrAsyncRibKind,
+ ClosureOrAsync,
/// We passed through an item scope. Disallow upvars.
- ItemRibKind(HasGenericParams),
+ Item(HasGenericParams),
/// We're in a constant item. Can't refer to dynamic stuff.
///
/// The item may reference generic parameters in trivial constant expressions.
/// All other constants aren't allowed to use generic params at all.
- ConstantItemRibKind(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>),
+ ConstantItem(ConstantHasGenerics, Option<(Ident, ConstantItemKind)>),
/// We passed through a module.
- ModuleRibKind(Module<'a>),
+ Module(Module<'a>),
/// We passed through a `macro_rules!` statement
MacroDefinition(DefId),
@@ -162,15 +200,15 @@ pub(crate) enum RibKind<'a> {
/// All bindings in this rib are generic parameters that can't be used
/// from the default of a generic parameter because they're not declared
/// before said generic parameter. Also see the `visit_generics` override.
- ForwardGenericParamBanRibKind,
+ ForwardGenericParamBan,
/// We are inside of the type of a const parameter. Can't refer to any
/// parameters.
- ConstParamTyRibKind,
+ ConstParamTy,
/// We are inside a `sym` inline assembly operand. Can only refer to
/// globals.
- InlineAsmSymRibKind,
+ InlineAsmSym,
}
impl RibKind<'_> {
@@ -178,30 +216,30 @@ impl RibKind<'_> {
/// variables.
pub(crate) fn contains_params(&self) -> bool {
match self {
- NormalRibKind
- | ClosureOrAsyncRibKind
- | ConstantItemRibKind(..)
- | ModuleRibKind(_)
- | MacroDefinition(_)
- | ConstParamTyRibKind
- | InlineAsmSymRibKind => false,
- AssocItemRibKind | ItemRibKind(_) | ForwardGenericParamBanRibKind => true,
+ RibKind::Normal
+ | RibKind::ClosureOrAsync
+ | RibKind::ConstantItem(..)
+ | RibKind::Module(_)
+ | RibKind::MacroDefinition(_)
+ | RibKind::ConstParamTy
+ | RibKind::InlineAsmSym => false,
+ RibKind::AssocItem | RibKind::Item(_) | RibKind::ForwardGenericParamBan => true,
}
}
/// This rib forbids referring to labels defined in upwards ribs.
fn is_label_barrier(self) -> bool {
match self {
- NormalRibKind | MacroDefinition(..) => false,
-
- AssocItemRibKind
- | ClosureOrAsyncRibKind
- | ItemRibKind(..)
- | ConstantItemRibKind(..)
- | ModuleRibKind(..)
- | ForwardGenericParamBanRibKind
- | ConstParamTyRibKind
- | InlineAsmSymRibKind => true,
+ RibKind::Normal | RibKind::MacroDefinition(..) => false,
+
+ RibKind::AssocItem
+ | RibKind::ClosureOrAsync
+ | RibKind::Item(..)
+ | RibKind::ConstantItem(..)
+ | RibKind::Module(..)
+ | RibKind::ForwardGenericParamBan
+ | RibKind::ConstParamTy
+ | RibKind::InlineAsmSym => true,
}
}
}
@@ -275,15 +313,18 @@ enum LifetimeRibKind {
/// Signal we cannot find which should be the anonymous lifetime.
ElisionFailure,
- /// FIXME(const_generics): This patches over an ICE caused by non-'static lifetimes in const
- /// generics. We are disallowing this until we can decide on how we want to handle non-'static
- /// lifetimes in const generics. See issue #74052 for discussion.
- ConstGeneric,
+ /// This rib forbids usage of generic parameters inside of const parameter types.
+ ///
+ /// While this is desirable to support eventually, it is difficult to do and so is
+ /// currently forbidden. See rust-lang/project-const-generics#28 for more info.
+ ConstParamTy,
- /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
- /// This function will emit an error if `generic_const_exprs` is not enabled, the body
- /// identified by `body_id` is an anonymous constant and `lifetime_ref` is non-static.
- AnonConst,
+ /// Usage of generic parameters is forbidden in various positions for anon consts:
+ /// - const arguments when `generic_const_exprs` is not enabled
+ /// - enum discriminant values
+ ///
+ /// This rib emits an error when a lifetime would resolve to a lifetime parameter.
+ ConcreteAnonConst(NoConstantGenericsReason),
/// This rib acts as a barrier to forbid reference to lifetimes of a parent item.
Item,
@@ -548,9 +589,6 @@ struct DiagnosticMetadata<'ast> {
/// they are used (in a `break` or `continue` statement)
unused_labels: FxHashMap<NodeId, Span>,
- /// Only used for better errors on `fn(): fn()`.
- current_type_ascription: Vec<Span>,
-
/// Only used for better errors on `let x = { foo: bar };`.
/// In the case of a parse error with `let x = { foo: bar, };`, this isn't needed, it's only
/// needed for cases where this parses as a correct type ascription.
@@ -653,13 +691,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_block(block);
self.parent_scope.macro_rules = old_macro_rules;
}
- fn visit_anon_const(&mut self, constant: &'ast AnonConst) {
- // We deal with repeat expressions explicitly in `resolve_expr`.
- self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
- this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
- this.resolve_anon_const(constant, IsRepeatExpr::No);
- })
- })
+ fn visit_anon_const(&mut self, _constant: &'ast AnonConst) {
+ bug!("encountered anon const without a manual call to `resolve_anon_const`");
}
fn visit_expr(&mut self, expr: &'ast Expr) {
self.resolve_expr(expr, None);
@@ -681,7 +714,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
fn visit_ty(&mut self, ty: &'ast Ty) {
let prev = self.diagnostic_metadata.current_trait_object;
let prev_ty = self.diagnostic_metadata.current_type_path;
- match ty.kind {
+ match &ty.kind {
TyKind::Ref(None, _) => {
// Elided lifetime in reference: we resolve as if there was some lifetime `'_` with
// NodeId `ty.id`.
@@ -690,7 +723,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.resolve_elided_lifetime(ty.id, span);
visit::walk_ty(self, ty);
}
- TyKind::Path(ref qself, ref path) => {
+ TyKind::Path(qself, path) => {
self.diagnostic_metadata.current_type_path = Some(ty);
self.smart_resolve_path(ty.id, &qself, path, PathSource::Type);
@@ -705,7 +738,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
let span = ty.span.shrink_to_lo().to(path.span.shrink_to_lo());
self.with_generic_param_rib(
&[],
- NormalRibKind,
+ RibKind::Normal,
LifetimeRibKind::Generics {
binder: ty.id,
kind: LifetimeBinderKind::PolyTrait,
@@ -735,15 +768,15 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
visit::walk_ty(self, ty);
self.lifetime_elision_candidates = candidates;
}
- TyKind::TraitObject(ref bounds, ..) => {
+ TyKind::TraitObject(bounds, ..) => {
self.diagnostic_metadata.current_trait_object = Some(&bounds[..]);
visit::walk_ty(self, ty)
}
- TyKind::BareFn(ref bare_fn) => {
+ TyKind::BareFn(bare_fn) => {
let span = ty.span.shrink_to_lo().to(bare_fn.decl_span.shrink_to_lo());
self.with_generic_param_rib(
&bare_fn.generic_params,
- NormalRibKind,
+ RibKind::Normal,
LifetimeRibKind::Generics {
binder: ty.id,
kind: LifetimeBinderKind::BareFnType,
@@ -774,6 +807,13 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
},
)
}
+ TyKind::Array(element_ty, length) => {
+ self.visit_ty(element_ty);
+ self.resolve_anon_const(length, AnonConstKind::ConstArg(IsRepeatExpr::No));
+ }
+ TyKind::Typeof(ct) => {
+ self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
+ }
_ => visit::walk_ty(self, ty),
}
self.diagnostic_metadata.current_trait_object = prev;
@@ -783,7 +823,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
let span = tref.span.shrink_to_lo().to(tref.trait_ref.path.span.shrink_to_lo());
self.with_generic_param_rib(
&tref.bound_generic_params,
- NormalRibKind,
+ RibKind::Normal,
LifetimeRibKind::Generics {
binder: tref.trait_ref.ref_id,
kind: LifetimeBinderKind::PolyTrait,
@@ -807,7 +847,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
ForeignItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: foreign_item.id,
kind: LifetimeBinderKind::Item,
@@ -819,7 +859,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
ForeignItemKind::Fn(box Fn { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: foreign_item.id,
kind: LifetimeBinderKind::Function,
@@ -859,13 +899,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
sig.decl.inputs.iter().map(|Param { ty, .. }| (None, &**ty)),
&sig.decl.output,
);
-
- this.record_lifetime_params_for_async(
- fn_id,
- sig.header.asyncness.opt_return_id(),
- );
},
);
+ self.record_lifetime_params_for_async(fn_id, sig.header.asyncness.opt_return_id());
return;
}
FnKind::Fn(..) => {
@@ -877,9 +913,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
debug!("(resolving function) entering function");
// Create a value rib for the function.
- self.with_rib(ValueNS, ClosureOrAsyncRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::ClosureOrAsync, |this| {
// Create a label rib for the function.
- this.with_label_rib(ClosureOrAsyncRibKind, |this| {
+ this.with_label_rib(RibKind::ClosureOrAsync, |this| {
match fn_kind {
FnKind::Fn(_, _, sig, _, generics, body) => {
this.visit_generics(generics);
@@ -1003,36 +1039,25 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
// namespace first, and if that fails we try again in the value namespace. If
// resolution in the value namespace succeeds, we have an generic const argument on
// our hands.
- if let TyKind::Path(ref qself, ref path) = ty.kind {
+ if let TyKind::Path(None, ref path) = ty.kind {
// We cannot disambiguate multi-segment paths right now as that requires type
// checking.
- if path.segments.len() == 1 && path.segments[0].args.is_none() {
+ if path.is_potential_trivial_const_arg() {
let mut check_ns = |ns| {
self.maybe_resolve_ident_in_lexical_scope(path.segments[0].ident, ns)
.is_some()
};
if !check_ns(TypeNS) && check_ns(ValueNS) {
- // This must be equivalent to `visit_anon_const`, but we cannot call it
- // directly due to visitor lifetimes so we have to copy-paste some code.
- //
- // Note that we might not be inside of an repeat expression here,
- // but considering that `IsRepeatExpr` is only relevant for
- // non-trivial constants this is doesn't matter.
- self.with_constant_rib(
- IsRepeatExpr::No,
- ConstantHasGenerics::Yes,
- None,
+ self.resolve_anon_const_manual(
+ true,
+ AnonConstKind::ConstArg(IsRepeatExpr::No),
|this| {
this.smart_resolve_path(
ty.id,
- qself,
+ &None,
path,
PathSource::Expr(None),
);
-
- if let Some(ref qself) = *qself {
- this.visit_ty(&qself.ty);
- }
this.visit_path(path, ty.id);
},
);
@@ -1046,7 +1071,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
self.visit_ty(ty);
}
GenericArg::Lifetime(lt) => self.visit_lifetime(lt, visit::LifetimeCtxt::GenericArg),
- GenericArg::Const(ct) => self.visit_anon_const(ct),
+ GenericArg::Const(ct) => {
+ self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::No))
+ }
}
self.diagnostic_metadata.currently_processing_generics = prev;
}
@@ -1062,7 +1089,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
match constraint.kind {
AssocConstraintKind::Equality { ref term } => match term {
Term::Ty(ty) => self.visit_ty(ty),
- Term::Const(c) => self.visit_anon_const(c),
+ Term::Const(c) => {
+ self.resolve_anon_const(c, AnonConstKind::ConstArg(IsRepeatExpr::No))
+ }
},
AssocConstraintKind::Bound { ref bounds } => {
walk_list!(self, visit_param_bound, bounds, BoundKind::Bound);
@@ -1079,7 +1108,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
for rib in self.lifetime_ribs.iter().rev() {
match rib.kind {
// We are inside a `PolyTraitRef`. The lifetimes are
- // to be intoduced in that (maybe implicit) `for<>` binder.
+ // to be introduced in that (maybe implicit) `for<>` binder.
LifetimeRibKind::Generics {
binder,
kind: LifetimeBinderKind::PolyTrait,
@@ -1111,8 +1140,8 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
| LifetimeRibKind::AnonymousReportError
| LifetimeRibKind::Elided(_)
| LifetimeRibKind::ElisionFailure
- | LifetimeRibKind::AnonConst
- | LifetimeRibKind::ConstGeneric => {}
+ | LifetimeRibKind::ConcreteAnonConst(_)
+ | LifetimeRibKind::ConstParamTy => {}
}
}
}
@@ -1136,7 +1165,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
let span = predicate_span.shrink_to_lo().to(bounded_ty.span.shrink_to_lo());
this.with_generic_param_rib(
&bound_generic_params,
- NormalRibKind,
+ RibKind::Normal,
LifetimeRibKind::Generics {
binder: bounded_ty.id,
kind: LifetimeBinderKind::WhereBound,
@@ -1173,7 +1202,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
InlineAsmOperand::Const { anon_const, .. } => {
// Although this is `DefKind::AnonConst`, it is allowed to reference outer
// generic parameters like an inline const.
- self.resolve_inline_const(anon_const);
+ self.resolve_anon_const(anon_const, AnonConstKind::InlineConst);
}
InlineAsmOperand::Sym { sym } => self.visit_inline_asm_sym(sym),
}
@@ -1182,9 +1211,9 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
fn visit_inline_asm_sym(&mut self, sym: &'ast InlineAsmSym) {
// This is similar to the code for AnonConst.
- self.with_rib(ValueNS, InlineAsmSymRibKind, |this| {
- this.with_rib(TypeNS, InlineAsmSymRibKind, |this| {
- this.with_label_rib(InlineAsmSymRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::InlineAsmSym, |this| {
+ this.with_rib(TypeNS, RibKind::InlineAsmSym, |this| {
+ this.with_label_rib(RibKind::InlineAsmSym, |this| {
this.smart_resolve_path(sym.id, &sym.qself, &sym.path, PathSource::Expr(None));
visit::walk_inline_asm_sym(this, sym);
});
@@ -1197,6 +1226,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
visit::walk_variant(self, v)
}
+ fn visit_variant_discr(&mut self, discr: &'ast AnonConst) {
+ self.resolve_anon_const(discr, AnonConstKind::EnumDiscriminant);
+ }
+
fn visit_field_def(&mut self, f: &'ast FieldDef) {
self.resolve_doc_links(&f.attrs, MaybeExported::Ok(f.id));
visit::walk_field_def(self, f)
@@ -1209,7 +1242,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// although it may be useful to track other components as well for diagnostics.
let graph_root = resolver.graph_root;
let parent_scope = ParentScope::module(graph_root, resolver);
- let start_rib_kind = ModuleRibKind(graph_root);
+ let start_rib_kind = RibKind::Module(graph_root);
LateResolutionVisitor {
r: resolver,
parent_scope,
@@ -1313,8 +1346,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(module) = self.r.get_module(self.r.local_def_id(id).to_def_id()) {
// Move down in the graph.
let orig_module = replace(&mut self.parent_scope.module, module);
- self.with_rib(ValueNS, ModuleRibKind(module), |this| {
- this.with_rib(TypeNS, ModuleRibKind(module), |this| {
+ self.with_rib(ValueNS, RibKind::Module(module), |this| {
+ this.with_rib(TypeNS, RibKind::Module(module), |this| {
let ret = f(this);
this.parent_scope.module = orig_module;
ret
@@ -1331,8 +1364,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// provide previous type parameters as they're built. We
// put all the parameters on the ban list and then remove
// them one by one as they are processed and become available.
- let mut forward_ty_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
- let mut forward_const_ban_rib = Rib::new(ForwardGenericParamBanRibKind);
+ let mut forward_ty_ban_rib = Rib::new(RibKind::ForwardGenericParamBan);
+ let mut forward_const_ban_rib = Rib::new(RibKind::ForwardGenericParamBan);
for param in params.iter() {
match param.kind {
GenericParamKind::Type { .. } => {
@@ -1393,9 +1426,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Const parameters can't have param bounds.
assert!(param.bounds.is_empty());
- this.ribs[TypeNS].push(Rib::new(ConstParamTyRibKind));
- this.ribs[ValueNS].push(Rib::new(ConstParamTyRibKind));
- this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
+ this.ribs[TypeNS].push(Rib::new(RibKind::ConstParamTy));
+ this.ribs[ValueNS].push(Rib::new(RibKind::ConstParamTy));
+ this.with_lifetime_rib(LifetimeRibKind::ConstParamTy, |this| {
this.visit_ty(ty)
});
this.ribs[TypeNS].pop().unwrap();
@@ -1404,9 +1437,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(ref expr) = default {
this.ribs[TypeNS].push(forward_ty_ban_rib);
this.ribs[ValueNS].push(forward_const_ban_rib);
- this.with_lifetime_rib(LifetimeRibKind::ConstGeneric, |this| {
- this.resolve_anon_const(expr, IsRepeatExpr::No)
- });
+ this.resolve_anon_const(
+ expr,
+ AnonConstKind::ConstArg(IsRepeatExpr::No),
+ );
forward_const_ban_rib = this.ribs[ValueNS].pop().unwrap();
forward_ty_ban_rib = this.ribs[TypeNS].pop().unwrap();
}
@@ -1458,7 +1492,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
if let Some(&(_, res)) = rib.bindings.get(&normalized_ident) {
self.record_lifetime_res(lifetime.id, res, LifetimeElisionCandidate::Named);
- if let LifetimeRes::Param { param, .. } = res {
+ if let LifetimeRes::Param { param, binder } = res {
match self.lifetime_uses.entry(param) {
Entry::Vacant(v) => {
debug!("First use of {:?} at {:?}", res, ident.span);
@@ -1472,10 +1506,16 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
LifetimeRibKind::Item
| LifetimeRibKind::AnonymousReportError
| LifetimeRibKind::ElisionFailure => Some(LifetimeUseSet::Many),
- // An anonymous lifetime is legal here, go ahead.
- LifetimeRibKind::AnonymousCreateParameter { .. } => {
- Some(LifetimeUseSet::One { use_span: ident.span, use_ctxt })
- }
+ // An anonymous lifetime is legal here, and bound to the right
+ // place, go ahead.
+ LifetimeRibKind::AnonymousCreateParameter {
+ binder: anon_binder,
+ ..
+ } => Some(if binder == anon_binder {
+ LifetimeUseSet::One { use_span: ident.span, use_ctxt }
+ } else {
+ LifetimeUseSet::Many
+ }),
// Only report if eliding the lifetime would have the same
// semantics.
LifetimeRibKind::Elided(r) => Some(if res == r {
@@ -1484,8 +1524,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
LifetimeUseSet::Many
}),
LifetimeRibKind::Generics { .. }
- | LifetimeRibKind::ConstGeneric => None,
- LifetimeRibKind::AnonConst => {
+ | LifetimeRibKind::ConstParamTy => None,
+ LifetimeRibKind::ConcreteAnonConst(_) => {
span_bug!(ident.span, "unexpected rib kind: {:?}", rib.kind)
}
})
@@ -1504,8 +1544,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
match rib.kind {
LifetimeRibKind::Item => break,
- LifetimeRibKind::ConstGeneric => {
- self.emit_non_static_lt_in_const_generic_error(lifetime);
+ LifetimeRibKind::ConstParamTy => {
+ self.emit_non_static_lt_in_const_param_ty_error(lifetime);
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Error,
@@ -1513,8 +1553,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
);
return;
}
- LifetimeRibKind::AnonConst => {
- self.maybe_emit_forbidden_non_static_lifetime_error(lifetime);
+ LifetimeRibKind::ConcreteAnonConst(cause) => {
+ self.emit_forbidden_non_static_lifetime_error(cause, lifetime);
self.record_lifetime_res(
lifetime.id,
LifetimeRes::Error,
@@ -1613,9 +1653,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
return;
}
LifetimeRibKind::Item => break,
- LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
- LifetimeRibKind::AnonConst => {
- // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+ LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
+ LifetimeRibKind::ConcreteAnonConst(_) => {
+ // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(lifetime.ident.span, "unexpected rib kind: {:?}", rib.kind)
}
}
@@ -1835,9 +1875,9 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.report_missing_lifetime_specifiers(vec![missing_lifetime], None);
break;
}
- LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstGeneric => {}
- LifetimeRibKind::AnonConst => {
- // There is always an `Elided(LifetimeRes::Static)` inside an `AnonConst`.
+ LifetimeRibKind::Generics { .. } | LifetimeRibKind::ConstParamTy => {}
+ LifetimeRibKind::ConcreteAnonConst(_) => {
+ // There is always an `Elided(LifetimeRes::Infer)` inside an `AnonConst`.
span_bug!(elided_lifetime_span, "unexpected rib kind: {:?}", rib.kind)
}
}
@@ -2079,6 +2119,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
visit::walk_ty(self, ty)
}
+
+ // A type may have an expression as a const generic argument.
+ // We do not want to recurse into those.
+ fn visit_expr(&mut self, _: &'a Expr) {}
}
let impl_self = self
@@ -2116,7 +2160,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
for i in (0..self.label_ribs.len()).rev() {
let rib = &self.label_ribs[i];
- if let MacroDefinition(def) = rib.kind {
+ if let RibKind::MacroDefinition(def) = rib.kind {
// If an invocation of this macro created `ident`, give up on `ident`
// and switch to `ident`'s source from the macro definition.
if def == self.r.macro_def(label.span.ctxt()) {
@@ -2164,7 +2208,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
self.with_current_self_item(item, |this| {
this.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::Item,
@@ -2205,7 +2249,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
this.r
.tcx
.sess
- .span_err(ident.span, &format!("imports cannot refer to {}", what));
+ .span_err(ident.span, format!("imports cannot refer to {}", what));
}
};
@@ -2245,7 +2289,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::TyAlias(box TyAlias { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::Item,
@@ -2258,7 +2302,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ItemKind::Fn(box Fn { ref generics, .. }) => {
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::Function,
@@ -2297,7 +2341,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::Item,
@@ -2318,7 +2362,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Create a new rib for the trait-wide type parameters.
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
binder: item.id,
kind: LifetimeBinderKind::Item,
@@ -2421,11 +2465,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let mut seen_lifetimes = FxHashSet::default();
// We also can't shadow bindings from the parent item
- if let AssocItemRibKind = kind {
+ if let RibKind::AssocItem = kind {
let mut add_bindings_for_ns = |ns| {
let parent_rib = self.ribs[ns]
.iter()
- .rfind(|r| matches!(r.kind, ItemRibKind(_)))
+ .rfind(|r| matches!(r.kind, RibKind::Item(_)))
.expect("associated item outside of an item");
seen_bindings.extend(parent_rib.bindings.keys().map(|ident| (*ident, ident.span)));
};
@@ -2514,8 +2558,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
};
let res = match kind {
- ItemRibKind(..) | AssocItemRibKind => Res::Def(def_kind, def_id.to_def_id()),
- NormalRibKind => {
+ RibKind::Item(..) | RibKind::AssocItem => Res::Def(def_kind, def_id.to_def_id()),
+ RibKind::Normal => {
if self.r.tcx.sess.features_untracked().non_lifetime_binders {
Res::Def(def_kind, def_id.to_def_id())
} else {
@@ -2561,11 +2605,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
fn with_static_rib(&mut self, f: impl FnOnce(&mut Self)) {
- let kind = ItemRibKind(HasGenericParams::No);
+ let kind = RibKind::Item(HasGenericParams::No);
self.with_rib(ValueNS, kind, |this| this.with_rib(TypeNS, kind, f))
}
- // HACK(min_const_generics,const_evaluatable_unchecked): We
+ // HACK(min_const_generics, generic_const_exprs): We
// want to keep allowing `[0; std::mem::size_of::<*mut T>()]`
// with a future compat lint for now. We do this by adding an
// additional special case for repeat expressions.
@@ -2581,18 +2625,26 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
item: Option<(Ident, ConstantItemKind)>,
f: impl FnOnce(&mut Self),
) {
- self.with_rib(ValueNS, ConstantItemRibKind(may_use_generics, item), |this| {
- this.with_rib(
- TypeNS,
- ConstantItemRibKind(
- may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
- item,
- ),
- |this| {
- this.with_label_rib(ConstantItemRibKind(may_use_generics, item), f);
- },
- )
- });
+ let f = |this: &mut Self| {
+ this.with_rib(ValueNS, RibKind::ConstantItem(may_use_generics, item), |this| {
+ this.with_rib(
+ TypeNS,
+ RibKind::ConstantItem(
+ may_use_generics.force_yes_if(is_repeat == IsRepeatExpr::Yes),
+ item,
+ ),
+ |this| {
+ this.with_label_rib(RibKind::ConstantItem(may_use_generics, item), f);
+ },
+ )
+ })
+ };
+
+ if let ConstantHasGenerics::No(cause) = may_use_generics {
+ self.with_lifetime_rib(LifetimeRibKind::ConcreteAnonConst(cause), f)
+ } else {
+ f(self)
+ }
}
fn with_current_self_type<T>(&mut self, self_type: &Ty, f: impl FnOnce(&mut Self) -> T) -> T {
@@ -2621,7 +2673,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
|this: &mut Self, generics: &Generics, kind, item: &'ast AssocItem| {
this.with_generic_param_rib(
&generics.params,
- AssocItemRibKind,
+ RibKind::AssocItem,
LifetimeRibKind::Generics { binder: item.id, span: generics.span, kind },
|this| visit::walk_assoc_item(this, item, AssocCtxt::Trait),
);
@@ -2702,7 +2754,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
fn with_self_rib_ns(&mut self, ns: Namespace, self_res: Res, f: impl FnOnce(&mut Self)) {
- let mut self_type_rib = Rib::new(NormalRibKind);
+ let mut self_type_rib = Rib::new(RibKind::Normal);
// Plain insert (no renaming, since types are not currently hygienic)
self_type_rib.bindings.insert(Ident::with_dummy_span(kw::SelfUpper), self_res);
@@ -2728,7 +2780,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// If applicable, create a rib for the type parameters.
self.with_generic_param_rib(
&generics.params,
- ItemRibKind(HasGenericParams::Yes(generics.span)),
+ RibKind::Item(HasGenericParams::Yes(generics.span)),
LifetimeRibKind::Generics {
span: generics.span,
binder: item_id,
@@ -2842,7 +2894,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// We also need a new scope for the impl item type parameters.
self.with_generic_param_rib(
&generics.params,
- AssocItemRibKind,
+ RibKind::AssocItem,
LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
@@ -2870,7 +2922,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// We also need a new scope for the impl item type parameters.
self.with_generic_param_rib(
&generics.params,
- AssocItemRibKind,
+ RibKind::AssocItem,
LifetimeRibKind::Generics {
binder: item.id,
span: generics.span,
@@ -2916,7 +2968,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// If there is a TraitRef in scope for an impl, then the method must be in the trait.
let Some((module, _)) = &self.current_trait_ref else { return; };
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
- let key = self.r.new_key(ident, ns);
+ let key = BindingKey::new(ident, ns);
let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
debug!(?binding);
if binding.is_none() {
@@ -2927,7 +2979,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
TypeNS => ValueNS,
_ => ns,
};
- let key = self.r.new_key(ident, ns);
+ let key = BindingKey::new(ident, ns);
binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
debug!(?binding);
}
@@ -3142,7 +3194,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
fn resolve_arm(&mut self, arm: &'ast Arm) {
- self.with_rib(ValueNS, NormalRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(&arm.pat, PatternSource::Match);
walk_list!(this, visit_expr, &arm.guard);
this.visit_expr(&arm.body);
@@ -3492,10 +3544,6 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
//
// Similar thing, for types, happens in `report_errors` above.
let report_errors_for_call = |this: &mut Self, parent_err: Spanned<ResolutionError<'a>>| {
- if !source.is_call() {
- return Some(parent_err);
- }
-
// Before we start looking for candidates, we have to get our hands
// on the type user is trying to perform invocation on; basically:
// we're transforming `HashMap::new` into just `HashMap`.
@@ -3803,7 +3851,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// use std::u8; // bring module u8 in scope
// fn f() -> u8 { // OK, resolves to primitive u8, not to std::u8
// u8::max_value() // OK, resolves to associated function <u8>::max_value,
- // // not to non-existent std::u8::max_value
+ // // not to nonexistent std::u8::max_value
// }
//
// Such behavior is required for backward compatibility.
@@ -3864,7 +3912,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
diagnostics::signal_label_shadowing(self.r.tcx.sess, orig_span, label.ident)
}
- self.with_label_rib(NormalRibKind, |this| {
+ self.with_label_rib(RibKind::Normal, |this| {
let ident = label.ident.normalize_to_macro_rules();
this.label_ribs.last_mut().unwrap().bindings.insert(ident, id);
f(this);
@@ -3887,11 +3935,11 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let mut num_macro_definition_ribs = 0;
if let Some(anonymous_module) = anonymous_module {
debug!("(resolving block) found anonymous module, moving down");
- self.ribs[ValueNS].push(Rib::new(ModuleRibKind(anonymous_module)));
- self.ribs[TypeNS].push(Rib::new(ModuleRibKind(anonymous_module)));
+ self.ribs[ValueNS].push(Rib::new(RibKind::Module(anonymous_module)));
+ self.ribs[TypeNS].push(Rib::new(RibKind::Module(anonymous_module)));
self.parent_scope.module = anonymous_module;
} else {
- self.ribs[ValueNS].push(Rib::new(NormalRibKind));
+ self.ribs[ValueNS].push(Rib::new(RibKind::Normal));
}
let prev = self.diagnostic_metadata.current_block_could_be_bare_struct_literal.take();
@@ -3908,8 +3956,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
&& let ItemKind::MacroDef(..) = item.kind {
num_macro_definition_ribs += 1;
let res = self.r.local_def_id(item.id).to_def_id();
- self.ribs[ValueNS].push(Rib::new(MacroDefinition(res)));
- self.label_ribs.push(Rib::new(MacroDefinition(res)));
+ self.ribs[ValueNS].push(Rib::new(RibKind::MacroDefinition(res)));
+ self.label_ribs.push(Rib::new(RibKind::MacroDefinition(res)));
}
self.visit_stmt(stmt);
@@ -3929,24 +3977,54 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
debug!("(resolving block) leaving block");
}
- fn resolve_anon_const(&mut self, constant: &'ast AnonConst, is_repeat: IsRepeatExpr) {
- debug!("resolve_anon_const {:?} is_repeat: {:?}", constant, is_repeat);
- self.with_constant_rib(
- is_repeat,
- if constant.value.is_potential_trivial_const_param() {
- ConstantHasGenerics::Yes
- } else {
- ConstantHasGenerics::No
- },
- None,
- |this| visit::walk_anon_const(this, constant),
+ fn resolve_anon_const(&mut self, constant: &'ast AnonConst, anon_const_kind: AnonConstKind) {
+ debug!(
+ "resolve_anon_const(constant: {:?}, anon_const_kind: {:?})",
+ constant, anon_const_kind
);
+
+ self.resolve_anon_const_manual(
+ constant.value.is_potential_trivial_const_arg(),
+ anon_const_kind,
+ |this| this.resolve_expr(&constant.value, None),
+ )
}
- fn resolve_inline_const(&mut self, constant: &'ast AnonConst) {
- debug!("resolve_anon_const {constant:?}");
- self.with_constant_rib(IsRepeatExpr::No, ConstantHasGenerics::Yes, None, |this| {
- visit::walk_anon_const(this, constant)
+ /// There are a few places that we need to resolve an anon const but we did not parse an
+ /// anon const so cannot provide an `&'ast AnonConst`. Right now this is just unbraced
+ /// const arguments that were parsed as type arguments, and `legact_const_generics` which
+ /// parse as normal function argument expressions. To avoid duplicating the code for resolving
+ /// an anon const we have this function which lets the caller manually call `resolve_expr` or
+ /// `smart_resolve_path`.
+ fn resolve_anon_const_manual(
+ &mut self,
+ is_trivial_const_arg: bool,
+ anon_const_kind: AnonConstKind,
+ resolve_expr: impl FnOnce(&mut Self),
+ ) {
+ let is_repeat_expr = match anon_const_kind {
+ AnonConstKind::ConstArg(is_repeat_expr) => is_repeat_expr,
+ _ => IsRepeatExpr::No,
+ };
+
+ let may_use_generics = match anon_const_kind {
+ AnonConstKind::EnumDiscriminant => {
+ ConstantHasGenerics::No(NoConstantGenericsReason::IsEnumDiscriminant)
+ }
+ AnonConstKind::InlineConst => ConstantHasGenerics::Yes,
+ AnonConstKind::ConstArg(_) => {
+ if self.r.tcx.features().generic_const_exprs || is_trivial_const_arg {
+ ConstantHasGenerics::Yes
+ } else {
+ ConstantHasGenerics::No(NoConstantGenericsReason::NonTrivialConstArg)
+ }
+ }
+ };
+
+ self.with_constant_rib(is_repeat_expr, may_use_generics, None, |this| {
+ this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Infer), |this| {
+ resolve_expr(this);
+ });
});
}
@@ -3996,7 +4074,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
ExprKind::If(ref cond, ref then, ref opt_else) => {
- self.with_rib(ValueNS, NormalRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::Normal, |this| {
let old = this.diagnostic_metadata.in_if_condition.replace(cond);
this.visit_expr(cond);
this.diagnostic_metadata.in_if_condition = old;
@@ -4013,7 +4091,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ExprKind::While(ref cond, ref block, label) => {
self.with_resolved_label(label, expr.id, |this| {
- this.with_rib(ValueNS, NormalRibKind, |this| {
+ this.with_rib(ValueNS, RibKind::Normal, |this| {
let old = this.diagnostic_metadata.in_if_condition.replace(cond);
this.visit_expr(cond);
this.diagnostic_metadata.in_if_condition = old;
@@ -4024,7 +4102,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ExprKind::ForLoop(ref pat, ref iter_expr, ref block, label) => {
self.visit_expr(iter_expr);
- self.with_rib(ValueNS, NormalRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::Normal, |this| {
this.resolve_pattern_top(pat, PatternSource::For);
this.resolve_labeled_block(label, expr.id, block);
});
@@ -4051,34 +4129,18 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// Constant arguments need to be treated as AnonConst since
// that is how they will be later lowered to HIR.
if const_args.contains(&idx) {
- self.with_constant_rib(
- IsRepeatExpr::No,
- if argument.is_potential_trivial_const_param() {
- ConstantHasGenerics::Yes
- } else {
- ConstantHasGenerics::No
- },
- None,
- |this| {
- this.resolve_expr(argument, None);
- },
+ self.resolve_anon_const_manual(
+ argument.is_potential_trivial_const_arg(),
+ AnonConstKind::ConstArg(IsRepeatExpr::No),
+ |this| this.resolve_expr(argument, None),
);
} else {
self.resolve_expr(argument, None);
}
}
}
- ExprKind::Type(ref type_expr, ref ty) => {
- // `ParseSess::type_ascription_path_suggestions` keeps spans of colon tokens in
- // type ascription. Here we are trying to retrieve the span of the colon token as
- // well, but only if it's written without spaces `expr:Ty` and therefore confusable
- // with `expr::Ty`, only in this case it will match the span from
- // `type_ascription_path_suggestions`.
- self.diagnostic_metadata
- .current_type_ascription
- .push(type_expr.span.between(ty.span));
+ ExprKind::Type(ref _type_expr, ref _ty) => {
visit::walk_expr(self, expr);
- self.diagnostic_metadata.current_type_ascription.pop();
}
// `async |x| ...` gets desugared to `|x| async {...}`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
@@ -4089,8 +4151,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
ref body,
..
}) => {
- self.with_rib(ValueNS, NormalRibKind, |this| {
- this.with_label_rib(ClosureOrAsyncRibKind, |this| {
+ self.with_rib(ValueNS, RibKind::Normal, |this| {
+ this.with_label_rib(RibKind::ClosureOrAsync, |this| {
// Resolve arguments:
this.resolve_params(&fn_decl.inputs);
// No need to resolve return type --
@@ -4114,7 +4176,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}) => {
self.with_generic_param_rib(
&generic_params,
- NormalRibKind,
+ RibKind::Normal,
LifetimeRibKind::Generics {
binder: expr.id,
kind: LifetimeBinderKind::Closure,
@@ -4125,18 +4187,14 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
ExprKind::Closure(..) => visit::walk_expr(self, expr),
ExprKind::Async(..) => {
- self.with_label_rib(ClosureOrAsyncRibKind, |this| visit::walk_expr(this, expr));
+ self.with_label_rib(RibKind::ClosureOrAsync, |this| visit::walk_expr(this, expr));
}
ExprKind::Repeat(ref elem, ref ct) => {
self.visit_expr(elem);
- self.with_lifetime_rib(LifetimeRibKind::AnonConst, |this| {
- this.with_lifetime_rib(LifetimeRibKind::Elided(LifetimeRes::Static), |this| {
- this.resolve_anon_const(ct, IsRepeatExpr::Yes)
- })
- });
+ self.resolve_anon_const(ct, AnonConstKind::ConstArg(IsRepeatExpr::Yes));
}
ExprKind::ConstBlock(ref ct) => {
- self.resolve_inline_const(ct);
+ self.resolve_anon_const(ct, AnonConstKind::InlineConst);
}
ExprKind::Index(ref elem, ref idx) => {
self.resolve_expr(elem, Some(expr));
@@ -4229,12 +4287,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
}
}
- fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> bool {
+ fn resolve_and_cache_rustdoc_path(&mut self, path_str: &str, ns: Namespace) -> Option<Res> {
// FIXME: This caching may be incorrect in case of multiple `macro_rules`
// items with the same name in the same module.
// Also hygiene is not considered.
let mut doc_link_resolutions = std::mem::take(&mut self.r.doc_link_resolutions);
- let res = doc_link_resolutions
+ let res = *doc_link_resolutions
.entry(self.parent_scope.module.nearest_parent_mod().expect_local())
.or_default()
.entry((Symbol::intern(path_str), ns))
@@ -4249,8 +4307,7 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
return None;
}
res
- })
- .is_some();
+ });
self.r.doc_link_resolutions = doc_link_resolutions;
res
}
@@ -4285,8 +4342,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
let mut any_resolved = false;
let mut need_assoc = false;
for ns in [TypeNS, ValueNS, MacroNS] {
- if self.resolve_and_cache_rustdoc_path(&path_str, ns) {
- any_resolved = true;
+ if let Some(res) = self.resolve_and_cache_rustdoc_path(&path_str, ns) {
+ // Rustdoc ignores tool attribute resolutions and attempts
+ // to resolve their prefixes for diagnostics.
+ any_resolved = !matches!(res, Res::NonMacroAttr(NonMacroAttrKind::Tool));
} else if ns != MacroNS {
need_assoc = true;
}
diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs
index 37fbfad2d..df6582580 100644
--- a/compiler/rustc_resolve/src/late/diagnostics.rs
+++ b/compiler/rustc_resolve/src/late/diagnostics.rs
@@ -1,7 +1,7 @@
use crate::diagnostics::{ImportSuggestion, LabelSuggestion, TypoSuggestion};
use crate::late::{AliasPossibility, LateResolutionVisitor, RibKind};
use crate::late::{LifetimeBinderKind, LifetimeRes, LifetimeRibKind, LifetimeUseSet};
-use crate::path_names_to_string;
+use crate::{errors, path_names_to_string};
use crate::{Module, ModuleKind, ModuleOrUniformRoot};
use crate::{PathResult, PathSource, Segment};
@@ -22,19 +22,20 @@ use rustc_hir::def::{self, CtorKind, CtorOf, DefKind};
use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
use rustc_hir::PrimTy;
use rustc_session::lint;
-use rustc_session::parse::feature_err;
use rustc_session::Session;
use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::symbol::{kw, sym, Ident, Symbol};
-use rustc_span::{BytePos, Span};
+use rustc_span::Span;
use std::iter;
use std::ops::Deref;
use thin_vec::ThinVec;
+use super::NoConstantGenericsReason;
+
type Res = def::Res<ast::NodeId>;
/// A field or associated item from self type suggested in case of resolution failure.
@@ -91,7 +92,7 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str
/// Description of an elided lifetime.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
pub(super) struct MissingLifetime {
- /// Used to overwrite the resolution with the suggestion, to avoid cascasing errors.
+ /// Used to overwrite the resolution with the suggestion, to avoid cascading errors.
pub id: NodeId,
/// Where to suggest adding the lifetime.
pub span: Span,
@@ -196,8 +197,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.sess
.source_map()
.span_to_snippet(span)
- .map(|snippet| snippet.ends_with(')'))
- .unwrap_or(false)
+ .is_ok_and(|snippet| snippet.ends_with(')'))
}
Res::Def(
DefKind::Ctor(..) | DefKind::AssocFn | DefKind::Const | DefKind::AssocConst,
@@ -315,8 +315,11 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
debug!(?res, ?source);
let base_error = self.make_base_error(path, span, source, res);
let code = source.error_code(res.is_some());
- let mut err =
- self.r.tcx.sess.struct_span_err_with_code(base_error.span, &base_error.msg, code);
+ let mut err = self.r.tcx.sess.struct_span_err_with_code(
+ base_error.span,
+ base_error.msg.clone(),
+ code,
+ );
self.suggest_swapping_misplaced_self_ty_and_trait(&mut err, source, res, base_error.span);
@@ -332,7 +335,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if self.suggest_pattern_match_with_let(&mut err, source, span) {
// Fallback label.
- err.span_label(base_error.span, &base_error.fallback_label);
+ err.span_label(base_error.span, base_error.fallback_label);
return (err, Vec::new());
}
@@ -350,18 +353,15 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
return (err, candidates);
}
- if !self.type_ascription_suggestion(&mut err, base_error.span) {
- let mut fallback =
- self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
+ let mut fallback = self.suggest_trait_and_bounds(&mut err, source, res, span, &base_error);
- // if we have suggested using pattern matching, then don't add needless suggestions
- // for typos.
- fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
+ // if we have suggested using pattern matching, then don't add needless suggestions
+ // for typos.
+ fallback |= self.suggest_typo(&mut err, source, path, span, &base_error);
- if fallback {
- // Fallback label.
- err.span_label(base_error.span, &base_error.fallback_label);
- }
+ if fallback {
+ // Fallback label.
+ err.span_label(base_error.span, base_error.fallback_label);
}
self.err_code_special_cases(&mut err, source, path, span);
@@ -408,7 +408,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
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).
+ // Emit help message for fake-self from other languages (e.g., `this` in JavaScript).
if ["this", "my"].contains(&item_str.as_str()) {
err.span_suggestion_short(
span,
@@ -494,24 +494,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.filter(|(_, enum_ty_path)| !enum_ty_path.starts_with("std::prelude::"))
.collect();
if !enum_candidates.is_empty() {
- if let (PathSource::Type, Some(span)) =
- (source, self.diagnostic_metadata.current_type_ascription.last())
- {
- if self
- .r
- .tcx
- .sess
- .parse_sess
- .type_ascription_path_suggestions
- .borrow()
- .contains(span)
- {
- // Already reported this issue on the lhs of the type ascription.
- err.downgrade_to_delayed_bug();
- return (true, candidates);
- }
- }
-
enum_candidates.sort();
// Contextualize for E0412 "cannot find type", but don't belabor the point
@@ -530,7 +512,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestions(
span,
- &msg,
+ msg,
enum_candidates.into_iter().map(|(_variant_path, enum_ty_path)| enum_ty_path),
Applicability::MachineApplicable,
);
@@ -577,7 +559,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
| AssocSuggestion::AssocType => {
err.span_suggestion(
span,
- &format!("you might have meant to {}", candidate.action()),
+ format!("you might have meant to {}", candidate.action()),
format!("Self::{path_str}"),
Applicability::MachineApplicable,
);
@@ -598,7 +580,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestion(
call_span,
- &format!("try calling `{ident}` as a method"),
+ format!("try calling `{ident}` as a method"),
format!("self.{path_str}({args_snippet})"),
Applicability::MachineApplicable,
);
@@ -623,14 +605,14 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
// Try to find in last block rib
- if let Some(rib) = &self.last_block_rib && let RibKind::NormalRibKind = rib.kind {
+ if let Some(rib) = &self.last_block_rib && let RibKind::Normal = rib.kind {
for (ident, &res) in &rib.bindings {
if let Res::Local(_) = res && path.len() == 1 &&
ident.span.eq_ctxt(path[0].ident.span) &&
ident.name == path[0].ident.name {
err.span_help(
ident.span,
- &format!("the binding `{}` is available in a different scope in the same function", path_str),
+ format!("the binding `{}` is available in a different scope in the same function", path_str),
);
return (true, candidates);
}
@@ -739,7 +721,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if let TypoCandidate::Shadowed(res, Some(sugg_span)) = typo_sugg
&& res
.opt_def_id()
- .map_or(false, |id| id.is_local() || is_in_same_file(span, sugg_span))
+ .is_some_and(|id| id.is_local() || is_in_same_file(span, sugg_span))
{
err.span_label(
sugg_span,
@@ -873,7 +855,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// The current function has a `self` parameter, but we were unable to resolve
// a reference to `self`. This can only happen if the `self` identifier we
// are resolving came from a different hygiene context.
- if fn_kind.decl().inputs.get(0).map_or(false, |p| p.is_self()) {
+ if fn_kind.decl().inputs.get(0).is_some_and(|p| p.is_self()) {
err.span_label(*span, "this function has a `self` parameter, but a macro invocation can only access identifiers it receives from parameters");
} else {
let doesnt = if is_assoc_fn {
@@ -911,7 +893,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if let Some(ident) = fn_kind.ident() {
err.span_label(
ident.span,
- &format!("this function {} have a `self` parameter", doesnt),
+ format!("this function {} have a `self` parameter", doesnt),
);
}
}
@@ -1087,7 +1069,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if ident.span == span {
err.span_suggestion_verbose(
*where_span,
- &format!("constrain the associated type to `{}`", ident),
+ format!("constrain the associated type to `{}`", ident),
format!(
"{}: {}<{} = {}>",
self.r
@@ -1288,7 +1270,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => {
let span = find_span(&source, err);
- err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here"));
+ err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
let (tail, descr, applicability, old_fields) = match source {
PathSource::Pat => ("", "pattern", Applicability::MachineApplicable, None),
@@ -1332,7 +1314,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
};
err.span_suggestion(
span,
- &format!("use struct {} syntax instead", descr),
+ format!("use struct {} syntax instead", descr),
format!("{path_str} {{{pad}{fields}{pad}}}"),
applicability,
);
@@ -1393,26 +1375,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
Res::Def(DefKind::Enum, def_id),
PathSource::TupleStruct(..) | PathSource::Expr(..),
) => {
- if self
- .diagnostic_metadata
- .current_type_ascription
- .last()
- .map(|sp| {
- self.r
- .tcx
- .sess
- .parse_sess
- .type_ascription_path_suggestions
- .borrow()
- .contains(&sp)
- })
- .unwrap_or(false)
- {
- err.downgrade_to_delayed_bug();
- // We already suggested changing `:` into `::` during parsing.
- return false;
- }
-
self.suggest_using_enum_variant(err, source, def_id, span);
}
(Res::Def(DefKind::Struct, def_id), source) if ns == ValueNS => {
@@ -1494,7 +1456,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
if non_visible_spans.len() > 0 {
if let Some(fields) = self.r.field_visibility_spans.get(&def_id) {
err.multipart_suggestion_verbose(
- &format!(
+ format!(
"consider making the field{} publicly accessible",
pluralize!(fields.len())
),
@@ -1524,7 +1486,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let span = find_span(&source, err);
err.span_label(
self.r.def_span(def_id),
- &format!("`{path_str}` defined here"),
+ format!("`{path_str}` defined here"),
);
err.span_suggestion(
span,
@@ -1538,7 +1500,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
(Res::Def(DefKind::Ctor(_, CtorKind::Fn), ctor_def_id), _) if ns == ValueNS => {
let def_id = self.r.tcx.parent(ctor_def_id);
- err.span_label(self.r.def_span(def_id), &format!("`{path_str}` defined here"));
+ err.span_label(self.r.def_span(def_id), format!("`{path_str}` defined here"));
let fields = self.r.field_def_ids(def_id).map_or_else(
|| "/* fields */".to_string(),
|field_ids| vec!["_"; field_ids.len()].join(", "),
@@ -1669,7 +1631,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
.tcx
.fn_arg_names(def_id)
.first()
- .map_or(false, |ident| ident.name == kw::SelfLower),
+ .is_some_and(|ident| ident.name == kw::SelfLower),
};
if has_self {
return Some(AssocSuggestion::MethodWithSelf { called });
@@ -1728,7 +1690,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
// Items in scope
- if let RibKind::ModuleRibKind(module) = rib.kind {
+ if let RibKind::Module(module) = rib.kind {
// Items from this module
self.r.add_module_candidates(module, &mut names, &filter_fn, Some(ctxt));
@@ -1817,80 +1779,6 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
})
}
- /// Only used in a specific case of type ascription suggestions
- fn get_colon_suggestion_span(&self, start: Span) -> Span {
- let sm = self.r.tcx.sess.source_map();
- start.to(sm.next_point(start))
- }
-
- fn type_ascription_suggestion(&self, err: &mut Diagnostic, base_span: Span) -> bool {
- let sm = self.r.tcx.sess.source_map();
- let base_snippet = sm.span_to_snippet(base_span);
- if let Some(&sp) = self.diagnostic_metadata.current_type_ascription.last() {
- if let Ok(snippet) = sm.span_to_snippet(sp) {
- let len = snippet.trim_end().len() as u32;
- if snippet.trim() == ":" {
- let colon_sp =
- sp.with_lo(sp.lo() + BytePos(len - 1)).with_hi(sp.lo() + BytePos(len));
- let mut show_label = true;
- if sm.is_multiline(sp) {
- err.span_suggestion_short(
- colon_sp,
- "maybe you meant to write `;` here",
- ";",
- Applicability::MaybeIncorrect,
- );
- } else {
- let after_colon_sp =
- self.get_colon_suggestion_span(colon_sp.shrink_to_hi());
- if snippet.len() == 1 {
- // `foo:bar`
- err.span_suggestion(
- colon_sp,
- "maybe you meant to write a path separator here",
- "::",
- Applicability::MaybeIncorrect,
- );
- show_label = false;
- if !self
- .r
- .tcx
- .sess
- .parse_sess
- .type_ascription_path_suggestions
- .borrow_mut()
- .insert(colon_sp)
- {
- err.downgrade_to_delayed_bug();
- }
- }
- if let Ok(base_snippet) = base_snippet {
- // Try to find an assignment
- let eq_span = sm.span_look_ahead(after_colon_sp, Some("="), Some(50));
- if let Ok(ref snippet) = sm.span_to_snippet(eq_span) && snippet == "=" {
- err.span_suggestion(
- base_span,
- "maybe you meant to write an assignment here",
- format!("let {}", base_snippet),
- Applicability::MaybeIncorrect,
- );
- show_label = false;
- }
- }
- }
- if show_label {
- err.span_label(
- base_span,
- "expecting a type here because of type ascription",
- );
- }
- return show_label;
- }
- }
- }
- false
- }
-
// 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 {
@@ -2014,7 +1902,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
err.span_suggestions(
span,
- &msg,
+ msg,
suggestable_variants,
Applicability::MaybeIncorrect,
);
@@ -2022,17 +1910,17 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
// If the enum has no tuple variants..
if non_suggestable_variant_count == variants.len() {
- err.help(&format!("the enum has no tuple variants {}", source_msg));
+ err.help(format!("the enum has no tuple variants {}", source_msg));
}
// If there are also non-tuple variants..
if non_suggestable_variant_count == 1 {
- err.help(&format!(
+ err.help(format!(
"you might have meant {} the enum's non-tuple variant",
source_msg
));
} else if non_suggestable_variant_count >= 1 {
- err.help(&format!(
+ err.help(format!(
"you might have meant {} one of the enum's non-tuple variants",
source_msg
));
@@ -2042,10 +1930,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
let def_id = self.r.tcx.parent(ctor_def_id);
match kind {
CtorKind::Const => false,
- CtorKind::Fn => !self
- .r
- .field_def_ids(def_id)
- .map_or(false, |field_ids| field_ids.is_empty()),
+ CtorKind::Fn => {
+ !self.r.field_def_ids(def_id).is_some_and(|field_ids| field_ids.is_empty())
+ }
}
};
@@ -2282,7 +2169,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
lint::builtin::SINGLE_USE_LIFETIMES,
param.id,
param.ident.span,
- &format!("lifetime parameter `{}` only used once", param.ident),
+ format!("lifetime parameter `{}` only used once", param.ident),
lint::BuiltinLintDiagnostics::SingleUseLifetime {
param_span: param.ident.span,
use_span: Some((use_span, elidable)),
@@ -2301,7 +2188,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
lint::builtin::UNUSED_LIFETIMES,
param.id,
param.ident.span,
- &format!("lifetime parameter `{}` never used", param.ident),
+ format!("lifetime parameter `{}` never used", param.ident),
lint::BuiltinLintDiagnostics::SingleUseLifetime {
param_span: param.ident.span,
use_span: None,
@@ -2367,7 +2254,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
suggest_note = false; // Avoid displaying the same help multiple times.
err.span_label(
span,
- &format!(
+ format!(
"lifetime `{}` is missing in item created through this procedural macro",
name,
),
@@ -2428,37 +2315,56 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
}
- pub(crate) fn emit_non_static_lt_in_const_generic_error(&self, lifetime_ref: &ast::Lifetime) {
- struct_span_err!(
- self.r.tcx.sess,
- lifetime_ref.ident.span,
- E0771,
- "use of non-static lifetime `{}` in const generic",
- lifetime_ref.ident
- )
- .note(
- "for more information, see issue #74052 \
- <https://github.com/rust-lang/rust/issues/74052>",
- )
- .emit();
+ pub(crate) fn emit_non_static_lt_in_const_param_ty_error(&self, lifetime_ref: &ast::Lifetime) {
+ self.r
+ .tcx
+ .sess
+ .create_err(errors::ParamInTyOfConstParam {
+ span: lifetime_ref.ident.span,
+ name: lifetime_ref.ident.name,
+ param_kind: Some(errors::ParamKindInTyOfConstParam::Lifetime),
+ })
+ .emit();
}
/// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics`.
/// This function will emit an error if `generic_const_exprs` is not enabled, the body identified by
/// `body_id` is an anonymous constant and `lifetime_ref` is non-static.
- pub(crate) fn maybe_emit_forbidden_non_static_lifetime_error(
+ pub(crate) fn emit_forbidden_non_static_lifetime_error(
&self,
+ cause: NoConstantGenericsReason,
lifetime_ref: &ast::Lifetime,
) {
- let feature_active = self.r.tcx.sess.features_untracked().generic_const_exprs;
- if !feature_active {
- feature_err(
- &self.r.tcx.sess.parse_sess,
- sym::generic_const_exprs,
- lifetime_ref.ident.span,
- "a non-static lifetime is not allowed in a `const`",
- )
- .emit();
+ match cause {
+ NoConstantGenericsReason::IsEnumDiscriminant => {
+ self.r
+ .tcx
+ .sess
+ .create_err(errors::ParamInEnumDiscriminant {
+ span: lifetime_ref.ident.span,
+ name: lifetime_ref.ident.name,
+ param_kind: errors::ParamKindInEnumDiscriminant::Lifetime,
+ })
+ .emit();
+ }
+ NoConstantGenericsReason::NonTrivialConstArg => {
+ assert!(!self.r.tcx.features().generic_const_exprs);
+ self.r
+ .tcx
+ .sess
+ .create_err(errors::ParamInNonTrivialAnonConst {
+ span: lifetime_ref.ident.span,
+ name: lifetime_ref.ident.name,
+ param_kind: errors::ParamKindInNonTrivialAnonConst::Lifetime,
+ help: self
+ .r
+ .tcx
+ .sess
+ .is_nightly_build()
+ .then_some(errors::ParamInNonTrivialAnonConstHelp),
+ })
+ .emit();
+ }
}
}
@@ -2573,13 +2479,13 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
)];
}
} else if num_params == 1 {
- err.help(&format!(
+ err.help(format!(
"this function's return type contains a borrowed value, \
but the signature does not say which {} it is borrowed from",
m
));
} else {
- err.help(&format!(
+ err.help(format!(
"this function's return type contains a borrowed value, \
but the signature does not say whether it is borrowed from {}",
m
@@ -2648,7 +2554,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
}
1 => {
err.multipart_suggestion_verbose(
- &format!("consider using the `{}` lifetime", existing_name),
+ format!("consider using the `{}` lifetime", existing_name),
spans_suggs,
Applicability::MaybeIncorrect,
);
@@ -2699,7 +2605,7 @@ pub(super) fn signal_label_shadowing(sess: &Session, orig: Span, shadower: Ident
let shadower = shadower.span;
let mut err = sess.struct_span_warn(
shadower,
- &format!("label name `{}` shadows a label name that is already in scope", name),
+ format!("label name `{}` shadows a label name that is already in scope", name),
);
err.span_label(orig, "first declared here");
err.span_label(shadower, format!("label `{}` already in scope", name));
diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs
index b820d56b8..3d2bd8429 100644
--- a/compiler/rustc_resolve/src/lib.rs
+++ b/compiler/rustc_resolve/src/lib.rs
@@ -21,6 +21,9 @@
#[macro_use]
extern crate tracing;
+use errors::{
+ ParamKindInEnumDiscriminant, ParamKindInNonTrivialAnonConst, ParamKindInTyOfConstParam,
+};
use rustc_arena::{DroplessArena, TypedArena};
use rustc_ast::node_id::NodeMap;
use rustc_ast::{self as ast, attr, NodeId, CRATE_NODE_ID};
@@ -33,17 +36,18 @@ use rustc_errors::{
Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage,
};
use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::def::Namespace::{self, *};
use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LocalDefIdMap, LocalDefIdSet};
use rustc_hir::def_id::{CRATE_DEF_ID, LOCAL_CRATE};
use rustc_hir::definitions::DefPathData;
use rustc_hir::TraitCandidate;
-use rustc_index::vec::IndexVec;
-use rustc_macros::fluent_messages;
+use rustc_index::IndexVec;
use rustc_metadata::creader::{CStore, CrateLoader};
use rustc_middle::metadata::ModChild;
use rustc_middle::middle::privacy::EffectiveVisibilities;
+use rustc_middle::query::Providers;
use rustc_middle::span_bug;
use rustc_middle::ty::{self, MainDefinition, RegisteredTools, TyCtxt};
use rustc_middle::ty::{ResolverGlobalCtxt, ResolverOutputs};
@@ -81,6 +85,7 @@ pub mod rustdoc;
fluent_messages! { "../messages.ftl" }
+#[derive(Debug)]
enum Weak {
Yes,
No,
@@ -101,7 +106,7 @@ impl Determinacy {
/// A specific scope in which a name can be looked up.
/// This enum is currently used only for early resolution (imports and macros),
/// but not for late resolution yet.
-#[derive(Clone, Copy)]
+#[derive(Clone, Copy, Debug)]
enum Scope<'a> {
DeriveHelpers(LocalExpnId),
DeriveHelpersCompat,
@@ -223,11 +228,15 @@ enum ResolutionError<'a> {
/// Error E0128: generic parameters with a default cannot use forward-declared identifiers.
ForwardDeclaredGenericParam,
/// ERROR E0770: the type of const parameters must not depend on other generic parameters.
- ParamInTyOfConstParam(Symbol),
+ ParamInTyOfConstParam { name: Symbol, param_kind: Option<ParamKindInTyOfConstParam> },
/// generic parameters must not be used inside const evaluations.
///
/// This error is only emitted when using `min_const_generics`.
- ParamInNonTrivialAnonConst { name: Symbol, is_type: bool },
+ ParamInNonTrivialAnonConst { name: Symbol, param_kind: ParamKindInNonTrivialAnonConst },
+ /// generic parameters must not be used inside enum discriminants.
+ ///
+ /// This error is emitted even with `generic_const_exprs`.
+ ParamInEnumDiscriminant { name: Symbol, param_kind: ParamKindInEnumDiscriminant },
/// Error E0735: generic parameters with a default cannot use `Self`
SelfInGenericParamDefault,
/// Error E0767: use of unreachable label
@@ -244,6 +253,8 @@ enum ResolutionError<'a> {
TraitImplDuplicate { name: Symbol, trait_item_span: Span, old_span: Span },
/// Inline asm `sym` operand must refer to a `fn` or `static`.
InvalidAsmSym,
+ /// `self` used instead of `Self` in a generic parameter
+ LowercaseSelf,
}
enum VisResolutionError<'a> {
@@ -459,6 +470,13 @@ struct BindingKey {
disambiguator: u32,
}
+impl BindingKey {
+ fn new(ident: Ident, ns: Namespace) -> Self {
+ let ident = ident.normalize_to_macros_2_0();
+ BindingKey { ident, ns, disambiguator: 0 }
+ }
+}
+
type Resolutions<'a> = RefCell<FxIndexMap<BindingKey, &'a RefCell<NameResolution<'a>>>>;
/// One node in the tree of modules.
@@ -909,8 +927,7 @@ pub struct Resolver<'a, 'tcx> {
/// `CrateNum` resolutions of `extern crate` items.
extern_crate_map: FxHashMap<LocalDefId, CrateNum>,
- module_children_non_reexports: LocalDefIdMap<Vec<LocalDefId>>,
- module_children_reexports: LocalDefIdMap<Vec<ModChild>>,
+ module_children: LocalDefIdMap<Vec<ModChild>>,
trait_map: NodeMap<Vec<TraitCandidate>>,
/// A map from nodes to anonymous modules.
@@ -934,6 +951,7 @@ pub struct Resolver<'a, 'tcx> {
empty_module: Module<'a>,
module_map: FxHashMap<DefId, Module<'a>>,
binding_parent_modules: FxHashMap<Interned<'a, NameBinding<'a>>, Module<'a>>,
+
underscore_disambiguator: u32,
/// Maps glob imports to the names of items actually imported.
@@ -1260,8 +1278,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
lifetimes_res_map: Default::default(),
extra_lifetime_params_map: Default::default(),
extern_crate_map: Default::default(),
- module_children_non_reexports: Default::default(),
- module_children_reexports: Default::default(),
+ module_children: Default::default(),
trait_map: NodeMap::default(),
underscore_disambiguator: 0,
empty_module,
@@ -1399,8 +1416,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
has_pub_restricted,
effective_visibilities,
extern_crate_map,
- module_children_non_reexports: self.module_children_non_reexports,
- module_children_reexports: self.module_children_reexports,
+ module_children: self.module_children,
glob_map,
maybe_unused_trait_imports,
main_def,
@@ -1461,7 +1477,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
fn is_builtin_macro(&mut self, res: Res) -> bool {
- self.get_macro(res).map_or(false, |macro_data| macro_data.ext.builtin_name.is_some())
+ self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some())
}
fn macro_def(&self, mut ctxt: SyntaxContext) -> DefId {
@@ -1588,7 +1604,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
import_ids
}
- fn new_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
+ fn new_disambiguated_key(&mut self, ident: Ident, ns: Namespace) -> BindingKey {
let ident = ident.normalize_to_macros_2_0();
let disambiguator = if ident.name == kw::Underscore {
self.underscore_disambiguator += 1;
@@ -2020,6 +2036,6 @@ impl Finalize {
}
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
providers.registered_tools = macros::registered_tools;
}
diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs
index 22b014c06..df5c16a93 100644
--- a/compiler/rustc_resolve/src/macros.rs
+++ b/compiler/rustc_resolve/src/macros.rs
@@ -1,7 +1,7 @@
//! A bunch of methods and structures more or less related to resolving macros and
//! interface provided by `Resolver` to macro expander.
-use crate::errors::{AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive};
+use crate::errors::{self, AddAsNonDerive, MacroExpectedFound, RemoveSurroundingDerive};
use crate::Namespace::*;
use crate::{BuiltinMacroState, Determinacy};
use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet};
@@ -121,7 +121,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
if let Some(old_ident) = registered_tools.replace(ident) {
let msg = format!("{} `{}` was already registered", "tool", ident);
tcx.sess
- .struct_span_err(ident.span, &msg)
+ .struct_span_err(ident.span, msg)
.span_label(old_ident.span, "already registered here")
.emit();
}
@@ -130,7 +130,7 @@ pub(crate) fn registered_tools(tcx: TyCtxt<'_>, (): ()) -> RegisteredTools {
let msg = format!("`{}` only accepts identifiers", sym::register_tool);
let span = nested_meta.span();
tcx.sess
- .struct_span_err(span, &msg)
+ .struct_span_err(span, msg)
.span_label(span, "not an identifier")
.emit();
}
@@ -202,7 +202,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
self.tcx
.sess
.diagnostic()
- .bug(&format!("built-in macro `{}` was already registered", name));
+ .bug(format!("built-in macro `{}` was already registered", name));
}
}
@@ -315,7 +315,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
UNUSED_MACROS,
node_id,
ident.span,
- &format!("unused macro definition: `{}`", ident.name),
+ format!("unused macro definition: `{}`", ident.name),
);
}
for (&(def_id, arm_i), &(ident, rule_span)) in self.unused_macro_rules.iter() {
@@ -328,7 +328,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
UNUSED_MACRO_RULES,
node_id,
rule_span,
- &format!(
+ format!(
"{} rule of macro `{}` is never used",
crate::diagnostics::ordinalize(arm_i + 1),
ident.name
@@ -436,9 +436,7 @@ impl<'a, 'tcx> ResolverExpand for Resolver<'a, 'tcx> {
// HACK(Urgau): This shouldn't be necessary
PathResult::Failed { is_error_from_last_segment: false, .. } => {
self.tcx.sess
- .struct_span_err(span, "not sure whether the path is accessible or not")
- .note("the type may have associated items, but we are currently not checking them")
- .emit();
+ .emit_err(errors::CfgAccessibleUnsure { span });
// If we get a partially resolved NonModule in one namespace, we should get the
// same result in any other namespaces, so we can return early.
@@ -513,10 +511,10 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if let Some(def_id) = def_id.as_local() {
self.unused_macros.remove(&def_id);
if self.proc_macro_stubs.contains(&def_id) {
- self.tcx.sess.span_err(
- path.span,
- "can't use a procedural macro from the same crate that defines it",
- );
+ self.tcx.sess.emit_err(errors::ProcMacroSameCrate {
+ span: path.span,
+ is_test: self.tcx.sess.is_test_crate(),
+ });
}
}
}
@@ -700,7 +698,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Segment::names_to_string(path)
);
let msg_note = "import resolution is stuck, try simplifying macro imports";
- this.tcx.sess.struct_span_err(span, &msg).note(msg_note).emit();
+ this.tcx.sess.struct_span_err(span, msg).note(msg_note).emit();
}
}
};
@@ -790,7 +788,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
Err(..) => {
let expected = kind.descr_expected();
let msg = format!("cannot find {} `{}` in this scope", expected, ident);
- let mut err = self.tcx.sess.struct_span_err(ident.span, &msg);
+ let mut err = self.tcx.sess.struct_span_err(ident.span, msg);
self.unresolved_macro_suggestions(&mut err, kind, &parent_scope, ident);
err.emit();
}
@@ -825,8 +823,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
let is_allowed = |feature| {
self.active_features.contains(&feature) || span.allows_unstable(feature)
};
- let allowed_by_implication =
- implied_by.map(|feature| is_allowed(feature)).unwrap_or(false);
+ let allowed_by_implication = implied_by.is_some_and(|feature| is_allowed(feature));
if !is_allowed(feature) && !allowed_by_implication {
let lint_buffer = &mut self.lint_buffer;
let soft_handler =
@@ -868,9 +865,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if kind != NonMacroAttrKind::Tool && binding.map_or(true, |b| b.is_import()) {
let msg =
format!("cannot use {} {} through an import", kind.article(), kind.descr());
- let mut err = self.tcx.sess.struct_span_err(span, &msg);
+ let mut err = self.tcx.sess.struct_span_err(span, msg);
if let Some(binding) = binding {
- err.span_note(binding.span, &format!("the {} imported here", kind.descr()));
+ err.span_note(binding.span, format!("the {} imported here", kind.descr()));
}
err.emit();
}
@@ -885,7 +882,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
if macro_kind.is_some() && sub_namespace_match(macro_kind, Some(MacroKind::Attr)) {
self.tcx.sess.span_err(
ident.span,
- &format!("name `{}` is reserved in attribute namespace", ident),
+ format!("name `{}` is reserved in attribute namespace", ident),
);
}
}
@@ -929,7 +926,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
}
} else {
let msg = format!("cannot find a built-in macro with name `{}`", item.ident);
- self.tcx.sess.span_err(item.span, &msg);
+ self.tcx.sess.span_err(item.span, msg);
}
}
diff --git a/compiler/rustc_resolve/src/rustdoc.rs b/compiler/rustc_resolve/src/rustdoc.rs
index 9eae99be2..d433391f2 100644
--- a/compiler/rustc_resolve/src/rustdoc.rs
+++ b/compiler/rustc_resolve/src/rustdoc.rs
@@ -367,6 +367,7 @@ fn preprocess_link(link: &str) -> Box<str> {
let link = link.strip_suffix("{}").unwrap_or(link);
let link = link.strip_suffix("[]").unwrap_or(link);
let link = if link != "!" { link.strip_suffix('!').unwrap_or(link) } else { link };
+ let link = link.trim();
strip_generics_from_path(link).unwrap_or_else(|_| link.into())
}
diff --git a/compiler/rustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml
index e4dbb8a63..604678068 100644
--- a/compiler/rustc_serialize/Cargo.toml
+++ b/compiler/rustc_serialize/Cargo.toml
@@ -10,3 +10,4 @@ thin-vec = "0.2.12"
[dev-dependencies]
rustc_macros = { path = "../rustc_macros" }
+tempfile = "3.2"
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs
index 7dad9aa01..e568b9e67 100644
--- a/compiler/rustc_serialize/src/leb128.rs
+++ b/compiler/rustc_serialize/src/leb128.rs
@@ -1,3 +1,6 @@
+use crate::opaque::MemDecoder;
+use crate::serialize::Decoder;
+
/// Returns the length of the longest LEB128 encoding for `T`, assuming `T` is an integer type
pub const fn max_leb128_len<T>() -> usize {
// The longest LEB128 encoding for an integer uses 7 bits per byte.
@@ -50,21 +53,19 @@ impl_write_unsigned_leb128!(write_usize_leb128, usize);
macro_rules! impl_read_unsigned_leb128 {
($fn_name:ident, $int_ty:ty) => {
#[inline]
- pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+ pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
// The first iteration of this loop is unpeeled. This is a
// performance win because this code is hot and integer values less
// than 128 are very common, typically occurring 50-80% or more of
// the time, even for u64 and u128.
- let byte = slice[*position];
- *position += 1;
+ let byte = decoder.read_u8();
if (byte & 0x80) == 0 {
return byte as $int_ty;
}
let mut result = (byte & 0x7F) as $int_ty;
let mut shift = 7;
loop {
- let byte = slice[*position];
- *position += 1;
+ let byte = decoder.read_u8();
if (byte & 0x80) == 0 {
result |= (byte as $int_ty) << shift;
return result;
@@ -127,14 +128,13 @@ impl_write_signed_leb128!(write_isize_leb128, isize);
macro_rules! impl_read_signed_leb128 {
($fn_name:ident, $int_ty:ty) => {
#[inline]
- pub fn $fn_name(slice: &[u8], position: &mut usize) -> $int_ty {
+ pub fn $fn_name(decoder: &mut MemDecoder<'_>) -> $int_ty {
let mut result = 0;
let mut shift = 0;
let mut byte;
loop {
- byte = slice[*position];
- *position += 1;
+ byte = decoder.read_u8();
result |= <$int_ty>::from(byte & 0x7F) << shift;
shift += 7;
diff --git a/compiler/rustc_serialize/src/lib.rs b/compiler/rustc_serialize/src/lib.rs
index 1f8d2336c..ce8503918 100644
--- a/compiler/rustc_serialize/src/lib.rs
+++ b/compiler/rustc_serialize/src/lib.rs
@@ -16,6 +16,7 @@ Core encoding and decoding interfaces.
#![feature(maybe_uninit_slice)]
#![feature(new_uninit)]
#![feature(allocator_api)]
+#![feature(ptr_sub_ptr)]
#![cfg_attr(test, feature(test))]
#![allow(rustc::internal)]
#![deny(rustc::untranslatable_diagnostic)]
diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs
index 53e5c8967..0ffc537ee 100644
--- a/compiler/rustc_serialize/src/opaque.rs
+++ b/compiler/rustc_serialize/src/opaque.rs
@@ -1,8 +1,10 @@
-use crate::leb128::{self, largest_max_leb128_len};
+use crate::leb128;
use crate::serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fs::File;
use std::io::{self, Write};
+use std::marker::PhantomData;
use std::mem::MaybeUninit;
+use std::ops::Range;
use std::path::Path;
use std::ptr;
@@ -10,147 +12,17 @@ use std::ptr;
// Encoder
// -----------------------------------------------------------------------------
-pub struct MemEncoder {
- pub data: Vec<u8>,
-}
-
-impl MemEncoder {
- pub fn new() -> MemEncoder {
- MemEncoder { data: vec![] }
- }
-
- #[inline]
- pub fn position(&self) -> usize {
- self.data.len()
- }
-
- pub fn finish(self) -> Vec<u8> {
- self.data
- }
-}
-
-macro_rules! write_leb128 {
- ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
- const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
- let old_len = $enc.data.len();
-
- if MAX_ENCODED_LEN > $enc.data.capacity() - old_len {
- $enc.data.reserve(MAX_ENCODED_LEN);
- }
-
- // SAFETY: The above check and `reserve` ensures that there is enough
- // room to write the encoded value to the vector's internal buffer.
- unsafe {
- let buf = &mut *($enc.data.as_mut_ptr().add(old_len)
- as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN]);
- let encoded = leb128::$fun(buf, $value);
- $enc.data.set_len(old_len + encoded.len());
- }
- }};
-}
-
-/// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
-/// This way we can skip validation and still be relatively sure that deserialization
-/// did not desynchronize.
-///
-/// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
-const STR_SENTINEL: u8 = 0xC1;
-
-impl Encoder for MemEncoder {
- #[inline]
- fn emit_usize(&mut self, v: usize) {
- write_leb128!(self, v, usize, write_usize_leb128)
- }
-
- #[inline]
- fn emit_u128(&mut self, v: u128) {
- write_leb128!(self, v, u128, write_u128_leb128);
- }
-
- #[inline]
- fn emit_u64(&mut self, v: u64) {
- write_leb128!(self, v, u64, write_u64_leb128);
- }
-
- #[inline]
- fn emit_u32(&mut self, v: u32) {
- write_leb128!(self, v, u32, write_u32_leb128);
- }
-
- #[inline]
- fn emit_u16(&mut self, v: u16) {
- self.data.extend_from_slice(&v.to_le_bytes());
- }
-
- #[inline]
- fn emit_u8(&mut self, v: u8) {
- self.data.push(v);
- }
-
- #[inline]
- fn emit_isize(&mut self, v: isize) {
- write_leb128!(self, v, isize, write_isize_leb128)
- }
-
- #[inline]
- fn emit_i128(&mut self, v: i128) {
- write_leb128!(self, v, i128, write_i128_leb128)
- }
-
- #[inline]
- fn emit_i64(&mut self, v: i64) {
- write_leb128!(self, v, i64, write_i64_leb128)
- }
-
- #[inline]
- fn emit_i32(&mut self, v: i32) {
- write_leb128!(self, v, i32, write_i32_leb128)
- }
-
- #[inline]
- fn emit_i16(&mut self, v: i16) {
- self.data.extend_from_slice(&v.to_le_bytes());
- }
-
- #[inline]
- fn emit_i8(&mut self, v: i8) {
- self.emit_u8(v as u8);
- }
-
- #[inline]
- fn emit_bool(&mut self, v: bool) {
- self.emit_u8(if v { 1 } else { 0 });
- }
-
- #[inline]
- fn emit_char(&mut self, v: char) {
- self.emit_u32(v as u32);
- }
-
- #[inline]
- fn emit_str(&mut self, v: &str) {
- self.emit_usize(v.len());
- self.emit_raw_bytes(v.as_bytes());
- self.emit_u8(STR_SENTINEL);
- }
-
- #[inline]
- fn emit_raw_bytes(&mut self, s: &[u8]) {
- self.data.extend_from_slice(s);
- }
-}
-
pub type FileEncodeResult = Result<usize, io::Error>;
+/// The size of the buffer in `FileEncoder`.
+const BUF_SIZE: usize = 8192;
+
/// `FileEncoder` encodes data to file via fixed-size buffer.
///
-/// When encoding large amounts of data to a file, using `FileEncoder` may be
-/// preferred over using `MemEncoder` to encode to a `Vec`, and then writing the
-/// `Vec` to file, as the latter uses as much memory as there is encoded data,
-/// while the former uses the fixed amount of memory allocated to the buffer.
-/// `FileEncoder` also has the advantage of not needing to reallocate as data
-/// is appended to it, but the disadvantage of requiring more error handling,
-/// which has some runtime overhead.
+/// There used to be a `MemEncoder` type that encoded all the data into a
+/// `Vec`. `FileEncoder` is better because its memory use is determined by the
+/// size of the buffer, rather than the full length of the encoded data, and
+/// because it doesn't need to reallocate memory along the way.
pub struct FileEncoder {
/// The input buffer. For adequate performance, we need more control over
/// buffering than `BufWriter` offers. If `BufWriter` ever offers a raw
@@ -166,26 +38,12 @@ pub struct FileEncoder {
impl FileEncoder {
pub fn new<P: AsRef<Path>>(path: P) -> io::Result<Self> {
- const DEFAULT_BUF_SIZE: usize = 8192;
- FileEncoder::with_capacity(path, DEFAULT_BUF_SIZE)
- }
-
- pub fn with_capacity<P: AsRef<Path>>(path: P, capacity: usize) -> io::Result<Self> {
- // Require capacity at least as large as the largest LEB128 encoding
- // here, so that we don't have to check or handle this on every write.
- assert!(capacity >= largest_max_leb128_len());
-
- // Require capacity small enough such that some capacity checks can be
- // done using guaranteed non-overflowing add rather than sub, which
- // shaves an instruction off those code paths (on x86 at least).
- assert!(capacity <= usize::MAX - largest_max_leb128_len());
-
// Create the file for reading and writing, because some encoders do both
// (e.g. the metadata encoder when -Zmeta-stats is enabled)
let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?;
Ok(FileEncoder {
- buf: Box::new_uninit_slice(capacity),
+ buf: Box::new_uninit_slice(BUF_SIZE),
buffered: 0,
flushed: 0,
file,
@@ -291,18 +149,10 @@ impl FileEncoder {
}
#[inline]
- fn capacity(&self) -> usize {
- self.buf.len()
- }
-
- #[inline]
fn write_one(&mut self, value: u8) {
- // We ensure this during `FileEncoder` construction.
- debug_assert!(self.capacity() >= 1);
-
let mut buffered = self.buffered;
- if std::intrinsics::unlikely(buffered >= self.capacity()) {
+ if std::intrinsics::unlikely(buffered + 1 > BUF_SIZE) {
self.flush();
buffered = 0;
}
@@ -318,13 +168,12 @@ impl FileEncoder {
#[inline]
fn write_all(&mut self, buf: &[u8]) {
- let capacity = self.capacity();
let buf_len = buf.len();
- if std::intrinsics::likely(buf_len <= capacity) {
+ if std::intrinsics::likely(buf_len <= BUF_SIZE) {
let mut buffered = self.buffered;
- if std::intrinsics::unlikely(buf_len > capacity - buffered) {
+ if std::intrinsics::unlikely(buffered + buf_len > BUF_SIZE) {
self.flush();
buffered = 0;
}
@@ -396,52 +245,39 @@ impl Drop for FileEncoder {
}
}
-macro_rules! file_encoder_write_leb128 {
- ($enc:expr, $value:expr, $int_ty:ty, $fun:ident) => {{
- const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
-
- // We ensure this during `FileEncoder` construction.
- debug_assert!($enc.capacity() >= MAX_ENCODED_LEN);
+macro_rules! write_leb128 {
+ ($this_fn:ident, $int_ty:ty, $write_leb_fn:ident) => {
+ #[inline]
+ fn $this_fn(&mut self, v: $int_ty) {
+ const MAX_ENCODED_LEN: usize = $crate::leb128::max_leb128_len::<$int_ty>();
- let mut buffered = $enc.buffered;
+ let mut buffered = self.buffered;
- // This can't overflow. See assertion in `FileEncoder::with_capacity`.
- if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > $enc.capacity()) {
- $enc.flush();
- buffered = 0;
- }
+ // This can't overflow because BUF_SIZE and MAX_ENCODED_LEN are both
+ // quite small.
+ if std::intrinsics::unlikely(buffered + MAX_ENCODED_LEN > BUF_SIZE) {
+ self.flush();
+ buffered = 0;
+ }
- // SAFETY: The above check and flush ensures that there is enough
- // room to write the encoded value to the buffer.
- let buf = unsafe {
- &mut *($enc.buf.as_mut_ptr().add(buffered) as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
- };
+ // SAFETY: The above check and flush ensures that there is enough
+ // room to write the encoded value to the buffer.
+ let buf = unsafe {
+ &mut *(self.buf.as_mut_ptr().add(buffered)
+ as *mut [MaybeUninit<u8>; MAX_ENCODED_LEN])
+ };
- let encoded = leb128::$fun(buf, $value);
- $enc.buffered = buffered + encoded.len();
- }};
+ let encoded = leb128::$write_leb_fn(buf, v);
+ self.buffered = buffered + encoded.len();
+ }
+ };
}
impl Encoder for FileEncoder {
- #[inline]
- fn emit_usize(&mut self, v: usize) {
- file_encoder_write_leb128!(self, v, usize, write_usize_leb128)
- }
-
- #[inline]
- fn emit_u128(&mut self, v: u128) {
- file_encoder_write_leb128!(self, v, u128, write_u128_leb128)
- }
-
- #[inline]
- fn emit_u64(&mut self, v: u64) {
- file_encoder_write_leb128!(self, v, u64, write_u64_leb128)
- }
-
- #[inline]
- fn emit_u32(&mut self, v: u32) {
- file_encoder_write_leb128!(self, v, u32, write_u32_leb128)
- }
+ write_leb128!(emit_usize, usize, write_usize_leb128);
+ write_leb128!(emit_u128, u128, write_u128_leb128);
+ write_leb128!(emit_u64, u64, write_u64_leb128);
+ write_leb128!(emit_u32, u32, write_u32_leb128);
#[inline]
fn emit_u16(&mut self, v: u16) {
@@ -453,25 +289,10 @@ impl Encoder for FileEncoder {
self.write_one(v);
}
- #[inline]
- fn emit_isize(&mut self, v: isize) {
- file_encoder_write_leb128!(self, v, isize, write_isize_leb128)
- }
-
- #[inline]
- fn emit_i128(&mut self, v: i128) {
- file_encoder_write_leb128!(self, v, i128, write_i128_leb128)
- }
-
- #[inline]
- fn emit_i64(&mut self, v: i64) {
- file_encoder_write_leb128!(self, v, i64, write_i64_leb128)
- }
-
- #[inline]
- fn emit_i32(&mut self, v: i32) {
- file_encoder_write_leb128!(self, v, i32, write_i32_leb128)
- }
+ write_leb128!(emit_isize, isize, write_isize_leb128);
+ write_leb128!(emit_i128, i128, write_i128_leb128);
+ write_leb128!(emit_i64, i64, write_i64_leb128);
+ write_leb128!(emit_i32, i32, write_i32_leb128);
#[inline]
fn emit_i16(&mut self, v: i16) {
@@ -479,28 +300,6 @@ impl Encoder for FileEncoder {
}
#[inline]
- fn emit_i8(&mut self, v: i8) {
- self.emit_u8(v as u8);
- }
-
- #[inline]
- fn emit_bool(&mut self, v: bool) {
- self.emit_u8(if v { 1 } else { 0 });
- }
-
- #[inline]
- fn emit_char(&mut self, v: char) {
- self.emit_u32(v as u32);
- }
-
- #[inline]
- fn emit_str(&mut self, v: &str) {
- self.emit_usize(v.len());
- self.emit_raw_bytes(v.as_bytes());
- self.emit_u8(STR_SENTINEL);
- }
-
- #[inline]
fn emit_raw_bytes(&mut self, s: &[u8]) {
self.write_all(s);
}
@@ -510,137 +309,155 @@ impl Encoder for FileEncoder {
// Decoder
// -----------------------------------------------------------------------------
+// Conceptually, `MemDecoder` wraps a `&[u8]` with a cursor into it that is always valid.
+// This is implemented with three pointers, two which represent the original slice and a
+// third that is our cursor.
+// It is an invariant of this type that start <= current <= end.
+// Additionally, the implementation of this type never modifies start and end.
pub struct MemDecoder<'a> {
- pub data: &'a [u8],
- position: usize,
+ start: *const u8,
+ current: *const u8,
+ end: *const u8,
+ _marker: PhantomData<&'a u8>,
}
impl<'a> MemDecoder<'a> {
#[inline]
pub fn new(data: &'a [u8], position: usize) -> MemDecoder<'a> {
- MemDecoder { data, position }
+ let Range { start, end } = data.as_ptr_range();
+ MemDecoder { start, current: data[position..].as_ptr(), end, _marker: PhantomData }
}
#[inline]
- pub fn position(&self) -> usize {
- self.position
+ pub fn data(&self) -> &'a [u8] {
+ // SAFETY: This recovers the original slice, only using members we never modify.
+ unsafe { std::slice::from_raw_parts(self.start, self.len()) }
}
#[inline]
- pub fn set_position(&mut self, pos: usize) {
- self.position = pos
+ pub fn len(&self) -> usize {
+ // SAFETY: This recovers the length of the original slice, only using members we never modify.
+ unsafe { self.end.sub_ptr(self.start) }
}
#[inline]
- pub fn advance(&mut self, bytes: usize) {
- self.position += bytes;
+ pub fn remaining(&self) -> usize {
+ // SAFETY: This type guarantees current <= end.
+ unsafe { self.end.sub_ptr(self.current) }
}
-}
-
-macro_rules! read_leb128 {
- ($dec:expr, $fun:ident) => {{ leb128::$fun($dec.data, &mut $dec.position) }};
-}
-impl<'a> Decoder for MemDecoder<'a> {
- #[inline]
- fn read_u128(&mut self) -> u128 {
- read_leb128!(self, read_u128_leb128)
+ #[cold]
+ #[inline(never)]
+ fn decoder_exhausted() -> ! {
+ panic!("MemDecoder exhausted")
}
#[inline]
- fn read_u64(&mut self) -> u64 {
- read_leb128!(self, read_u64_leb128)
+ fn read_array<const N: usize>(&mut self) -> [u8; N] {
+ self.read_raw_bytes(N).try_into().unwrap()
}
+ /// While we could manually expose manipulation of the decoder position,
+ /// all current users of that method would need to reset the position later,
+ /// incurring the bounds check of set_position twice.
#[inline]
- fn read_u32(&mut self) -> u32 {
- read_leb128!(self, read_u32_leb128)
- }
+ pub fn with_position<F, T>(&mut self, pos: usize, func: F) -> T
+ where
+ F: Fn(&mut MemDecoder<'a>) -> T,
+ {
+ struct SetOnDrop<'a, 'guarded> {
+ decoder: &'guarded mut MemDecoder<'a>,
+ current: *const u8,
+ }
+ impl Drop for SetOnDrop<'_, '_> {
+ fn drop(&mut self) {
+ self.decoder.current = self.current;
+ }
+ }
- #[inline]
- fn read_u16(&mut self) -> u16 {
- let bytes = [self.data[self.position], self.data[self.position + 1]];
- let value = u16::from_le_bytes(bytes);
- self.position += 2;
- value
+ if pos >= self.len() {
+ Self::decoder_exhausted();
+ }
+ let previous = self.current;
+ // SAFETY: We just checked if this add is in-bounds above.
+ unsafe {
+ self.current = self.start.add(pos);
+ }
+ let guard = SetOnDrop { current: previous, decoder: self };
+ func(guard.decoder)
}
+}
- #[inline]
- fn read_u8(&mut self) -> u8 {
- let value = self.data[self.position];
- self.position += 1;
- value
- }
+macro_rules! read_leb128 {
+ ($this_fn:ident, $int_ty:ty, $read_leb_fn:ident) => {
+ #[inline]
+ fn $this_fn(&mut self) -> $int_ty {
+ leb128::$read_leb_fn(self)
+ }
+ };
+}
- #[inline]
- fn read_usize(&mut self) -> usize {
- read_leb128!(self, read_usize_leb128)
- }
+impl<'a> Decoder for MemDecoder<'a> {
+ read_leb128!(read_usize, usize, read_usize_leb128);
+ read_leb128!(read_u128, u128, read_u128_leb128);
+ read_leb128!(read_u64, u64, read_u64_leb128);
+ read_leb128!(read_u32, u32, read_u32_leb128);
#[inline]
- fn read_i128(&mut self) -> i128 {
- read_leb128!(self, read_i128_leb128)
+ fn read_u16(&mut self) -> u16 {
+ u16::from_le_bytes(self.read_array())
}
#[inline]
- fn read_i64(&mut self) -> i64 {
- read_leb128!(self, read_i64_leb128)
+ fn read_u8(&mut self) -> u8 {
+ if self.current == self.end {
+ Self::decoder_exhausted();
+ }
+ // SAFETY: This type guarantees current <= end, and we just checked current == end.
+ unsafe {
+ let byte = *self.current;
+ self.current = self.current.add(1);
+ byte
+ }
}
- #[inline]
- fn read_i32(&mut self) -> i32 {
- read_leb128!(self, read_i32_leb128)
- }
+ read_leb128!(read_isize, isize, read_isize_leb128);
+ read_leb128!(read_i128, i128, read_i128_leb128);
+ read_leb128!(read_i64, i64, read_i64_leb128);
+ read_leb128!(read_i32, i32, read_i32_leb128);
#[inline]
fn read_i16(&mut self) -> i16 {
- let bytes = [self.data[self.position], self.data[self.position + 1]];
- let value = i16::from_le_bytes(bytes);
- self.position += 2;
- value
- }
-
- #[inline]
- fn read_i8(&mut self) -> i8 {
- let value = self.data[self.position];
- self.position += 1;
- value as i8
- }
-
- #[inline]
- fn read_isize(&mut self) -> isize {
- read_leb128!(self, read_isize_leb128)
+ i16::from_le_bytes(self.read_array())
}
#[inline]
- fn read_bool(&mut self) -> bool {
- let value = self.read_u8();
- value != 0
- }
-
- #[inline]
- fn read_char(&mut self) -> char {
- let bits = self.read_u32();
- std::char::from_u32(bits).unwrap()
+ fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
+ if bytes > self.remaining() {
+ Self::decoder_exhausted();
+ }
+ // SAFETY: We just checked if this range is in-bounds above.
+ unsafe {
+ let slice = std::slice::from_raw_parts(self.current, bytes);
+ self.current = self.current.add(bytes);
+ slice
+ }
}
#[inline]
- fn read_str(&mut self) -> &'a str {
- let len = self.read_usize();
- let sentinel = self.data[self.position + len];
- assert!(sentinel == STR_SENTINEL);
- let s = unsafe {
- std::str::from_utf8_unchecked(&self.data[self.position..self.position + len])
- };
- self.position += len + 1;
- s
+ fn peek_byte(&self) -> u8 {
+ if self.current == self.end {
+ Self::decoder_exhausted();
+ }
+ // SAFETY: This type guarantees current is inbounds or one-past-the-end, which is end.
+ // Since we just checked current == end, the current pointer must be inbounds.
+ unsafe { *self.current }
}
#[inline]
- fn read_raw_bytes(&mut self, bytes: usize) -> &'a [u8] {
- let start = self.position;
- self.position += bytes;
- &self.data[start..self.position]
+ fn position(&self) -> usize {
+ // SAFETY: This type guarantees start <= current
+ unsafe { self.current.sub_ptr(self.start) }
}
}
@@ -651,13 +468,6 @@ impl<'a> Decoder for MemDecoder<'a> {
// Specialize encoding byte slices. This specialization also applies to encoding `Vec<u8>`s, etc.,
// since the default implementations call `encode` on their slices internally.
-impl Encodable<MemEncoder> for [u8] {
- fn encode(&self, e: &mut MemEncoder) {
- Encoder::emit_usize(e, self.len());
- e.emit_raw_bytes(self);
- }
-}
-
impl Encodable<FileEncoder> for [u8] {
fn encode(&self, e: &mut FileEncoder) {
Encoder::emit_usize(e, self.len());
@@ -681,16 +491,6 @@ impl IntEncodedWithFixedSize {
pub const ENCODED_SIZE: usize = 8;
}
-impl Encodable<MemEncoder> for IntEncodedWithFixedSize {
- #[inline]
- fn encode(&self, e: &mut MemEncoder) {
- let _start_pos = e.position();
- e.emit_raw_bytes(&self.0.to_le_bytes());
- let _end_pos = e.position();
- debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
- }
-}
-
impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
#[inline]
fn encode(&self, e: &mut FileEncoder) {
@@ -704,12 +504,7 @@ impl Encodable<FileEncoder> for IntEncodedWithFixedSize {
impl<'a> Decodable<MemDecoder<'a>> for IntEncodedWithFixedSize {
#[inline]
fn decode(decoder: &mut MemDecoder<'a>) -> IntEncodedWithFixedSize {
- let _start_pos = decoder.position();
- let bytes = decoder.read_raw_bytes(IntEncodedWithFixedSize::ENCODED_SIZE);
- let value = u64::from_le_bytes(bytes.try_into().unwrap());
- let _end_pos = decoder.position();
- debug_assert_eq!((_end_pos - _start_pos), IntEncodedWithFixedSize::ENCODED_SIZE);
-
- IntEncodedWithFixedSize(value)
+ let bytes = decoder.read_array::<{ IntEncodedWithFixedSize::ENCODED_SIZE }>();
+ IntEncodedWithFixedSize(u64::from_le_bytes(bytes))
}
}
diff --git a/compiler/rustc_serialize/src/serialize.rs b/compiler/rustc_serialize/src/serialize.rs
index 527abc237..06166cabc 100644
--- a/compiler/rustc_serialize/src/serialize.rs
+++ b/compiler/rustc_serialize/src/serialize.rs
@@ -1,9 +1,5 @@
//! Support code for encoding and decoding types.
-/*
-Core encoding and decoding interfaces.
-*/
-
use std::alloc::Allocator;
use std::borrow::Cow;
use std::cell::{Cell, RefCell};
@@ -12,6 +8,13 @@ use std::path;
use std::rc::Rc;
use std::sync::Arc;
+/// A byte that [cannot occur in UTF8 sequences][utf8]. Used to mark the end of a string.
+/// This way we can skip validation and still be relatively sure that deserialization
+/// did not desynchronize.
+///
+/// [utf8]: https://en.wikipedia.org/w/index.php?title=UTF-8&oldid=1058865525#Codepage_layout
+const STR_SENTINEL: u8 = 0xC1;
+
/// A note about error handling.
///
/// Encoders may be fallible, but in practice failure is rare and there are so
@@ -28,22 +31,41 @@ use std::sync::Arc;
/// really makes sense to store floating-point values at all.
/// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
pub trait Encoder {
- // Primitive types:
fn emit_usize(&mut self, v: usize);
fn emit_u128(&mut self, v: u128);
fn emit_u64(&mut self, v: u64);
fn emit_u32(&mut self, v: u32);
fn emit_u16(&mut self, v: u16);
fn emit_u8(&mut self, v: u8);
+
fn emit_isize(&mut self, v: isize);
fn emit_i128(&mut self, v: i128);
fn emit_i64(&mut self, v: i64);
fn emit_i32(&mut self, v: i32);
fn emit_i16(&mut self, v: i16);
- fn emit_i8(&mut self, v: i8);
- fn emit_bool(&mut self, v: bool);
- fn emit_char(&mut self, v: char);
- fn emit_str(&mut self, v: &str);
+
+ #[inline]
+ fn emit_i8(&mut self, v: i8) {
+ self.emit_u8(v as u8);
+ }
+
+ #[inline]
+ fn emit_bool(&mut self, v: bool) {
+ self.emit_u8(if v { 1 } else { 0 });
+ }
+
+ #[inline]
+ fn emit_char(&mut self, v: char) {
+ self.emit_u32(v as u32);
+ }
+
+ #[inline]
+ fn emit_str(&mut self, v: &str) {
+ self.emit_usize(v.len());
+ self.emit_raw_bytes(v.as_bytes());
+ self.emit_u8(STR_SENTINEL);
+ }
+
fn emit_raw_bytes(&mut self, s: &[u8]);
fn emit_enum_variant<F>(&mut self, v_id: usize, f: F)
@@ -67,23 +89,52 @@ pub trait Encoder {
/// really makes sense to store floating-point values at all.
/// (If you need it, revert <https://github.com/rust-lang/rust/pull/109984>.)
pub trait Decoder {
- // Primitive types:
fn read_usize(&mut self) -> usize;
fn read_u128(&mut self) -> u128;
fn read_u64(&mut self) -> u64;
fn read_u32(&mut self) -> u32;
fn read_u16(&mut self) -> u16;
fn read_u8(&mut self) -> u8;
+
fn read_isize(&mut self) -> isize;
fn read_i128(&mut self) -> i128;
fn read_i64(&mut self) -> i64;
fn read_i32(&mut self) -> i32;
fn read_i16(&mut self) -> i16;
- fn read_i8(&mut self) -> i8;
- fn read_bool(&mut self) -> bool;
- fn read_char(&mut self) -> char;
- fn read_str(&mut self) -> &str;
+
+ #[inline]
+ fn read_i8(&mut self) -> i8 {
+ self.read_u8() as i8
+ }
+
+ #[inline]
+ fn read_bool(&mut self) -> bool {
+ let value = self.read_u8();
+ value != 0
+ }
+
+ #[inline]
+ fn read_char(&mut self) -> char {
+ let bits = self.read_u32();
+ std::char::from_u32(bits).unwrap()
+ }
+
+ #[inline]
+ fn read_str(&mut self) -> &str {
+ let len = self.read_usize();
+ let bytes = self.read_raw_bytes(len + 1);
+ assert!(bytes[len] == STR_SENTINEL);
+ unsafe { std::str::from_utf8_unchecked(&bytes[..len]) }
+ }
+
fn read_raw_bytes(&mut self, len: usize) -> &[u8];
+
+ // Although there is an `emit_enum_variant` method in `Encoder`, the code
+ // patterns in decoding are different enough to encoding that there is no
+ // need for a corresponding `read_enum_variant` method here.
+
+ fn peek_byte(&self) -> u8;
+ fn position(&self) -> usize;
}
/// Trait for types that can be serialized
diff --git a/compiler/rustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs
index 314c07db9..7872e7784 100644
--- a/compiler/rustc_serialize/tests/leb128.rs
+++ b/compiler/rustc_serialize/tests/leb128.rs
@@ -3,6 +3,7 @@
use rustc_serialize::leb128::*;
use std::mem::MaybeUninit;
+use rustc_serialize::Decoder;
macro_rules! impl_test_unsigned_leb128 {
($test_name:ident, $write_fn_name:ident, $read_fn_name:ident, $int_ty:ident) => {
@@ -28,12 +29,12 @@ macro_rules! impl_test_unsigned_leb128 {
stream.extend($write_fn_name(&mut buf, x));
}
- let mut position = 0;
+ let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
for &expected in &values {
- let actual = $read_fn_name(&stream, &mut position);
+ let actual = $read_fn_name(&mut decoder);
assert_eq!(expected, actual);
}
- assert_eq!(stream.len(), position);
+ assert_eq!(stream.len(), decoder.position());
}
};
}
@@ -74,12 +75,12 @@ macro_rules! impl_test_signed_leb128 {
stream.extend($write_fn_name(&mut buf, x));
}
- let mut position = 0;
+ let mut decoder = rustc_serialize::opaque::MemDecoder::new(&stream, 0);
for &expected in &values {
- let actual = $read_fn_name(&stream, &mut position);
+ let actual = $read_fn_name(&mut decoder);
assert_eq!(expected, actual);
}
- assert_eq!(stream.len(), position);
+ assert_eq!(stream.len(), decoder.position());
}
};
}
diff --git a/compiler/rustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs
index 5e7dd18aa..861091688 100644
--- a/compiler/rustc_serialize/tests/opaque.rs
+++ b/compiler/rustc_serialize/tests/opaque.rs
@@ -1,9 +1,10 @@
#![allow(rustc::internal)]
use rustc_macros::{Decodable, Encodable};
-use rustc_serialize::opaque::{MemDecoder, MemEncoder};
+use rustc_serialize::opaque::{MemDecoder, FileEncoder};
use rustc_serialize::{Decodable, Encodable};
use std::fmt::Debug;
+use std::fs;
#[derive(PartialEq, Clone, Debug, Encodable, Decodable)]
struct Struct {
@@ -27,18 +28,21 @@ struct Struct {
}
fn check_round_trip<
- T: Encodable<MemEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
+ T: Encodable<FileEncoder> + for<'a> Decodable<MemDecoder<'a>> + PartialEq + Debug,
>(
values: Vec<T>,
) {
- let mut encoder = MemEncoder::new();
+ let tmpfile = tempfile::NamedTempFile::new().unwrap();
+ let tmpfile = tmpfile.path();
+
+ let mut encoder = FileEncoder::new(&tmpfile).unwrap();
for value in &values {
Encodable::encode(value, &mut encoder);
}
+ encoder.finish().unwrap();
- let data = encoder.finish();
+ let data = fs::read(&tmpfile).unwrap();
let mut decoder = MemDecoder::new(&data[..], 0);
-
for value in values {
let decoded = Decodable::decode(&mut decoder);
assert_eq!(value, decoded);
@@ -61,7 +65,7 @@ fn test_u8() {
#[test]
fn test_u16() {
- for i in u16::MIN..u16::MAX {
+ for i in [u16::MIN, 111, 3333, 55555, u16::MAX] {
check_round_trip(vec![1, 2, 3, i, i, i]);
}
}
@@ -92,7 +96,7 @@ fn test_i8() {
#[test]
fn test_i16() {
- for i in i16::MIN..i16::MAX {
+ for i in [i16::MIN, -100, 0, 101, i16::MAX] {
check_round_trip(vec![-1, 2, -3, i, i, i, 2]);
}
}
@@ -251,3 +255,41 @@ fn test_tuples() {
check_round_trip(vec![(1234567isize, 100000000000000u64, 99999999999999i64)]);
check_round_trip(vec![(String::new(), "some string".to_string())]);
}
+
+#[test]
+fn test_unit_like_struct() {
+ #[derive(Encodable, Decodable, PartialEq, Debug)]
+ struct UnitLikeStruct;
+
+ check_round_trip(vec![UnitLikeStruct]);
+}
+
+#[test]
+fn test_box() {
+ #[derive(Encodable, Decodable, PartialEq, Debug)]
+ struct A {
+ foo: Box<[bool]>,
+ }
+
+ let obj = A { foo: Box::new([true, false]) };
+ check_round_trip(vec![obj]);
+}
+
+#[test]
+fn test_cell() {
+ use std::cell::{Cell, RefCell};
+
+ #[derive(Encodable, Decodable, PartialEq, Debug)]
+ struct A {
+ baz: isize,
+ }
+
+ #[derive(Encodable, Decodable, PartialEq, Debug)]
+ struct B {
+ foo: Cell<bool>,
+ bar: RefCell<A>,
+ }
+
+ let obj = B { foo: Cell::new(true), bar: RefCell::new(A { baz: 2 }) };
+ check_round_trip(vec![obj]);
+}
diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml
index 9e337dde9..3af83aaaa 100644
--- a/compiler/rustc_session/Cargo.toml
+++ b/compiler/rustc_session/Cargo.toml
@@ -10,10 +10,10 @@ tracing = "0.1"
rustc_errors = { path = "../rustc_errors" }
rustc_feature = { path = "../rustc_feature" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_data_structures = { path = "../rustc_data_structures" }
-rustc_index = { path = "../rustc_index" }
rustc_span = { path = "../rustc_span" }
rustc_fs_util = { path = "../rustc_fs_util" }
rustc_ast = { path = "../rustc_ast" }
@@ -25,7 +25,7 @@ termize = "0.1.1"
libc = "0.2"
[target.'cfg(windows)'.dependencies.windows]
-version = "0.46.0"
+version = "0.48.0"
features = [
"Win32_Foundation",
"Win32_System_LibraryLoader",
diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl
index ff53f22d4..5a0b8f9f7 100644
--- a/compiler/rustc_session/messages.ftl
+++ b/compiler/rustc_session/messages.ftl
@@ -1,13 +1,20 @@
-session_incorrect_cgu_reuse_type =
- CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
- [one] {"at least "}
- *[other] {""}
- }`{$expected_reuse}`
+session_binary_float_literal_not_supported = binary float literal is not supported
+session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64
+
+session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+
+session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
session_cgu_not_recorded =
CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded
-session_feature_gate_error = {$explain}
+session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`
+
+session_crate_name_empty = crate name must not be empty
+
+session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
+
+session_expr_parentheses_needed = parentheses are required to parse this as an expression
session_feature_diagnostic_for_issue =
see issue #{$n} <https://github.com/rust-lang/rust/issues/{$n}> for more information
@@ -15,81 +22,84 @@ session_feature_diagnostic_for_issue =
session_feature_diagnostic_help =
add `#![feature({$feature})]` to the crate attributes to enable
-session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
+session_feature_gate_error = {$explain}
-session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
+session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
-session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
+session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
+session_incorrect_cgu_reuse_type =
+ CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least ->
+ [one] {"at least "}
+ *[other] {""}
+ }`{$expected_reuse}`
-session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
+session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
-session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
+session_int_literal_too_large = integer literal is too large
+ .note = value exceeds limit of `{$limit}`
-session_instrumentation_not_supported = {$us} instrumentation is not supported for this target
+session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
-session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
+session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
+ .label = invalid suffix `{$suffix}`
+ .help = valid suffixes are `f32` and `f64`
-session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
+session_invalid_float_literal_width = invalid width `{$width}` for float literal
+ .help = valid widths are 32 and 64
-session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}`
+session_invalid_int_literal_width = invalid width `{$width}` for integer literal
+ .help = valid widths are 8, 16, 32, 64 and 128
-session_cannot_enable_crt_static_linux = sanitizer is incompatible with statically linked libc, disable it using `-C target-feature=-crt-static`
+session_invalid_literal_suffix = suffixes on {$kind} literals are invalid
+ .label = invalid suffix `{$suffix}`
-session_sanitizer_cfi_enabled = `-Zsanitizer=cfi` requires `-Clto`
+session_invalid_num_literal_base_prefix = invalid base prefix for number literal
+ .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
+ .suggestion = try making the prefix lowercase
-session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
+session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
+ .label = invalid suffix `{$suffix}`
+ .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
-session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
+session_linker_plugin_lto_windows_not_supported = linker plugin based LTO is not supported together with `-C prefer-dynamic` when targeting Windows-like targets
-session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
+session_not_circumvent_feature = `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine
-session_branch_protection_requires_aarch64 = `-Zbranch-protection` is only supported on aarch64
+session_not_supported = not supported
-session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
+session_nul_in_c_str = null characters in C string literals are not supported
-session_file_is_not_writeable = output file {$file} is not writeable -- check its permissions
+session_octal_float_literal_not_supported = octal float literal is not supported
+session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
-session_crate_name_does_not_match = `--crate-name` and `#[crate_name]` are required to match, but `{$s}` != `{$name}`
+session_profile_sample_use_file_does_not_exist = file `{$path}` passed to `-C profile-sample-use` does not exist.
-session_crate_name_invalid = crate names cannot start with a `-`, but `{$s}` has a leading hyphen
+session_profile_use_file_does_not_exist = file `{$path}` passed to `-C profile-use` does not exist.
-session_crate_name_empty = crate name must not be empty
+session_sanitizer_cfi_canonical_jump_tables_requires_cfi = `-Zsanitizer-cfi-canonical-jump-tables` requires `-Zsanitizer=cfi`
-session_invalid_character_in_create_name = invalid character `{$character}` in crate name: `{$crate_name}`
+session_sanitizer_cfi_generalize_pointers_requires_cfi = `-Zsanitizer-cfi-generalize-pointers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
-session_expr_parentheses_needed = parentheses are required to parse this as an expression
+session_sanitizer_cfi_normalize_integers_requires_cfi = `-Zsanitizer-cfi-normalize-integers` requires `-Zsanitizer=cfi` or `-Zsanitizer=kcfi`
-session_skipping_const_checks = skipping const checks
-session_unleashed_feature_help_named = skipping check for `{$gate}` feature
-session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
+session_sanitizer_cfi_requires_lto = `-Zsanitizer=cfi` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
-session_hexadecimal_float_literal_not_supported = hexadecimal float literal is not supported
-session_octal_float_literal_not_supported = octal float literal is not supported
-session_binary_float_literal_not_supported = binary float literal is not supported
-session_not_supported = not supported
+session_sanitizer_not_supported = {$us} sanitizer is not supported for this target
-session_invalid_literal_suffix = suffixes on {$kind} literals are invalid
- .label = invalid suffix `{$suffix}`
+session_sanitizers_not_supported = {$us} sanitizers are not supported for this target
-session_invalid_num_literal_base_prefix = invalid base prefix for number literal
- .note = base prefixes (`0xff`, `0b1010`, `0o755`) are lowercase
- .suggestion = try making the prefix lowercase
+session_skipping_const_checks = skipping const checks
+session_split_debuginfo_unstable_platform = `-Csplit-debuginfo={$debuginfo}` is unstable on this platform
-session_invalid_num_literal_suffix = invalid suffix `{$suffix}` for number literal
- .label = invalid suffix `{$suffix}`
- .help = the suffix must be one of the numeric types (`u32`, `isize`, `f32`, etc.)
+session_split_lto_unit_requires_lto = `-Zsplit-lto-unit` requires `-Clto`, `-Clto=thin`, or `-Clinker-plugin-lto`
-session_invalid_float_literal_width = invalid width `{$width}` for float literal
- .help = valid widths are 32 and 64
+session_target_requires_unwind_tables = target requires unwind tables, they cannot be disabled with `-C force-unwind-tables=no`
-session_invalid_float_literal_suffix = invalid suffix `{$suffix}` for float literal
- .label = invalid suffix `{$suffix}`
- .help = valid suffixes are `f32` and `f64`
+session_target_stack_protector_not_supported = `-Z stack-protector={$stack_protector}` is not supported for target {$target_triple} and will be ignored
-session_int_literal_too_large = integer literal is too large
- .note = value exceeds limit of `{$limit}`
+session_unleashed_feature_help_named = skipping check for `{$gate}` feature
+session_unleashed_feature_help_unnamed = skipping check that does not even have a feature gate
-session_invalid_int_literal_width = invalid width `{$width}` for integer literal
- .help = valid widths are 8, 16, 32, 64 and 128
+session_unstable_virtual_function_elimination = `-Zvirtual-function-elimination` requires `-Clto`
-session_optimization_fuel_exhausted = optimization-fuel-exhausted: {$msg}
+session_unsupported_dwarf_version = requested DWARF version {$dwarf_version} is greater than 5
diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs
index 79eb31bb1..6c8c8e484 100644
--- a/compiler/rustc_session/src/config.rs
+++ b/compiler/rustc_session/src/config.rs
@@ -421,7 +421,7 @@ pub enum TrimmedDefPaths {
GoodPath,
}
-#[derive(Clone, Hash)]
+#[derive(Clone, Hash, Debug)]
pub enum ResolveDocLinks {
/// Do not resolve doc links.
None,
@@ -518,6 +518,12 @@ pub struct ExternEntry {
/// `--extern nounused:std=/path/to/lib/libstd.rlib`. This is used to
/// suppress `unused-crate-dependencies` warnings.
pub nounused_dep: bool,
+ /// If the extern entry is not referenced in the crate, force it to be resolved anyway.
+ ///
+ /// Allows a dependency satisfying, for instance, a missing panic handler to be injected
+ /// without modifying source:
+ /// `--extern force:extras=/path/to/lib/libstd.rlib`
+ pub force: bool,
}
#[derive(Clone, Debug)]
@@ -556,7 +562,13 @@ impl Externs {
impl ExternEntry {
fn new(location: ExternLocation) -> ExternEntry {
- ExternEntry { location, is_private_dep: false, add_prelude: false, nounused_dep: false }
+ ExternEntry {
+ location,
+ is_private_dep: false,
+ add_prelude: false,
+ nounused_dep: false,
+ force: false,
+ }
}
pub fn files(&self) -> Option<impl Iterator<Item = &CanonicalizedPath>> {
@@ -587,6 +599,7 @@ pub enum PrintRequest {
StackProtectorStrategies,
LinkArgs,
SplitDebuginfo,
+ DeploymentTarget,
}
#[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)]
@@ -1036,9 +1049,20 @@ fn default_configuration(sess: &Session) -> CrateConfig {
ret.insert((sym::sanitize, Some(symbol)));
}
+ if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ ret.insert((sym::sanitizer_cfi_generalize_pointers, None));
+ }
+
+ if sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ ret.insert((sym::sanitizer_cfi_normalize_integers, None));
+ }
+
if sess.opts.debug_assertions {
ret.insert((sym::debug_assertions, None));
}
+ if sess.overflow_checks() {
+ ret.insert((sym::overflow_checks, None));
+ }
// JUSTIFICATION: before wrapper fn is available
#[allow(rustc::bad_opt_access)]
if sess.opts.crate_types.contains(&CrateType::ProcMacro) {
@@ -1056,37 +1080,76 @@ pub fn to_crate_config(cfg: FxHashSet<(String, Option<String>)>) -> CrateConfig
/// The parsed `--check-cfg` options
pub struct CheckCfg<T = String> {
- /// The set of all `names()`, if None no name checking is performed
- pub names_valid: Option<FxHashSet<T>>,
+ /// Is well known names activated
+ pub exhaustive_names: bool,
/// Is well known values activated
- pub well_known_values: bool,
- /// The set of all `values()`
- pub values_valid: FxHashMap<T, FxHashSet<T>>,
+ pub exhaustive_values: bool,
+ /// All the expected values for a config name
+ pub expecteds: FxHashMap<T, ExpectedValues<T>>,
}
impl<T> Default for CheckCfg<T> {
fn default() -> Self {
CheckCfg {
- names_valid: Default::default(),
- values_valid: Default::default(),
- well_known_values: false,
+ exhaustive_names: false,
+ exhaustive_values: false,
+ expecteds: FxHashMap::default(),
}
}
}
impl<T> CheckCfg<T> {
- fn map_data<O: Eq + Hash>(&self, f: impl Fn(&T) -> O) -> CheckCfg<O> {
+ fn map_data<O: Eq + Hash>(self, f: impl Fn(T) -> O) -> CheckCfg<O> {
CheckCfg {
- names_valid: self
- .names_valid
- .as_ref()
- .map(|names_valid| names_valid.iter().map(|a| f(a)).collect()),
- values_valid: self
- .values_valid
- .iter()
- .map(|(a, b)| (f(a), b.iter().map(|b| f(b)).collect()))
+ exhaustive_names: self.exhaustive_names,
+ exhaustive_values: self.exhaustive_values,
+ expecteds: self
+ .expecteds
+ .into_iter()
+ .map(|(name, values)| {
+ (
+ f(name),
+ match values {
+ ExpectedValues::Some(values) => ExpectedValues::Some(
+ values.into_iter().map(|b| b.map(|b| f(b))).collect(),
+ ),
+ ExpectedValues::Any => ExpectedValues::Any,
+ },
+ )
+ })
.collect(),
- well_known_values: self.well_known_values,
+ }
+ }
+}
+
+pub enum ExpectedValues<T> {
+ Some(FxHashSet<Option<T>>),
+ Any,
+}
+
+impl<T: Eq + Hash> ExpectedValues<T> {
+ fn insert(&mut self, value: T) -> bool {
+ match self {
+ ExpectedValues::Some(expecteds) => expecteds.insert(Some(value)),
+ ExpectedValues::Any => false,
+ }
+ }
+}
+
+impl<T: Eq + Hash> Extend<T> for ExpectedValues<T> {
+ fn extend<I: IntoIterator<Item = T>>(&mut self, iter: I) {
+ match self {
+ ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(Some)),
+ ExpectedValues::Any => {}
+ }
+ }
+}
+
+impl<'a, T: Eq + Hash + Copy + 'a> Extend<&'a T> for ExpectedValues<T> {
+ fn extend<I: IntoIterator<Item = &'a T>>(&mut self, iter: I) {
+ match self {
+ ExpectedValues::Some(expecteds) => expecteds.extend(iter.into_iter().map(|a| Some(*a))),
+ ExpectedValues::Any => {}
}
}
}
@@ -1095,58 +1158,27 @@ impl<T> CheckCfg<T> {
/// `rustc_interface::interface::Config` accepts this in the compiler configuration,
/// but the symbol interner is not yet set up then, so we must convert it later.
pub fn to_crate_check_config(cfg: CheckCfg) -> CrateCheckConfig {
- cfg.map_data(|s| Symbol::intern(s))
+ cfg.map_data(|s| Symbol::intern(&s))
}
impl CrateCheckConfig {
- /// Fills a `CrateCheckConfig` with well-known configuration names.
- fn fill_well_known_names(&mut self) {
- // NOTE: This should be kept in sync with `default_configuration` and
- // `fill_well_known_values`
- const WELL_KNOWN_NAMES: &[Symbol] = &[
- // rustc
- sym::unix,
- sym::windows,
- sym::target_os,
- sym::target_family,
- sym::target_arch,
- sym::target_endian,
- sym::target_pointer_width,
- sym::target_env,
- sym::target_abi,
- sym::target_vendor,
- sym::target_thread_local,
- sym::target_has_atomic_load_store,
- sym::target_has_atomic,
- sym::target_has_atomic_equal_alignment,
- sym::target_feature,
- sym::panic,
- sym::sanitize,
- sym::debug_assertions,
- sym::proc_macro,
- sym::test,
- sym::feature,
- // rustdoc
- sym::doc,
- sym::doctest,
- // miri
- sym::miri,
- ];
-
- // We only insert well-known names if `names()` was activated
- if let Some(names_valid) = &mut self.names_valid {
- names_valid.extend(WELL_KNOWN_NAMES);
- }
- }
-
- /// Fills a `CrateCheckConfig` with well-known configuration values.
- fn fill_well_known_values(&mut self, current_target: &Target) {
- if !self.well_known_values {
+ pub fn fill_well_known(&mut self, current_target: &Target) {
+ if !self.exhaustive_values && !self.exhaustive_names {
return;
}
- // NOTE: This should be kept in sync with `default_configuration` and
- // `fill_well_known_names`
+ let no_values = || {
+ let mut values = FxHashSet::default();
+ values.insert(None);
+ ExpectedValues::Some(values)
+ };
+
+ let empty_values = || {
+ let values = FxHashSet::default();
+ ExpectedValues::Some(values)
+ };
+
+ // NOTE: This should be kept in sync with `default_configuration`
let panic_values = &PanicStrategy::all();
@@ -1166,6 +1198,9 @@ impl CrateCheckConfig {
// Unknown possible values:
// - `feature`
// - `target_feature`
+ for name in [sym::feature, sym::target_feature] {
+ self.expecteds.entry(name).or_insert(ExpectedValues::Any);
+ }
// No-values
for name in [
@@ -1177,22 +1212,26 @@ impl CrateCheckConfig {
sym::windows,
sym::proc_macro,
sym::debug_assertions,
+ sym::overflow_checks,
sym::target_thread_local,
] {
- self.values_valid.entry(name).or_default();
+ self.expecteds.entry(name).or_insert_with(no_values);
}
// Pre-defined values
- self.values_valid.entry(sym::panic).or_default().extend(panic_values);
- self.values_valid.entry(sym::sanitize).or_default().extend(sanitize_values);
- self.values_valid.entry(sym::target_has_atomic).or_default().extend(atomic_values);
- self.values_valid
+ self.expecteds.entry(sym::panic).or_insert_with(empty_values).extend(panic_values);
+ self.expecteds.entry(sym::sanitize).or_insert_with(empty_values).extend(sanitize_values);
+ self.expecteds
+ .entry(sym::target_has_atomic)
+ .or_insert_with(no_values)
+ .extend(atomic_values);
+ self.expecteds
.entry(sym::target_has_atomic_load_store)
- .or_default()
+ .or_insert_with(no_values)
.extend(atomic_values);
- self.values_valid
+ self.expecteds
.entry(sym::target_has_atomic_equal_alignment)
- .or_default()
+ .or_insert_with(no_values)
.extend(atomic_values);
// Target specific values
@@ -1210,47 +1249,50 @@ impl CrateCheckConfig {
// Initialize (if not already initialized)
for &e in VALUES {
- self.values_valid.entry(e).or_default();
+ let entry = self.expecteds.entry(e);
+ if !self.exhaustive_values {
+ entry.or_insert(ExpectedValues::Any);
+ } else {
+ entry.or_insert_with(empty_values);
+ }
}
- // Get all values map at once otherwise it would be costly.
- // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
- let [
- values_target_os,
- values_target_family,
- values_target_arch,
- values_target_endian,
- values_target_env,
- values_target_abi,
- values_target_vendor,
- values_target_pointer_width,
- ] = self
- .values_valid
- .get_many_mut(VALUES)
- .expect("unable to get all the check-cfg values buckets");
-
- for target in TARGETS
- .iter()
- .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
- .chain(iter::once(current_target.clone()))
- {
- values_target_os.insert(Symbol::intern(&target.options.os));
- values_target_family
- .extend(target.options.families.iter().map(|family| Symbol::intern(family)));
- values_target_arch.insert(Symbol::intern(&target.arch));
- values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
- values_target_env.insert(Symbol::intern(&target.options.env));
- values_target_abi.insert(Symbol::intern(&target.options.abi));
- values_target_vendor.insert(Symbol::intern(&target.options.vendor));
- values_target_pointer_width.insert(sym::integer(target.pointer_width));
+ if self.exhaustive_values {
+ // Get all values map at once otherwise it would be costly.
+ // (8 values * 220 targets ~= 1760 times, at the time of writing this comment).
+ let [
+ values_target_os,
+ values_target_family,
+ values_target_arch,
+ values_target_endian,
+ values_target_env,
+ values_target_abi,
+ values_target_vendor,
+ values_target_pointer_width,
+ ] = self
+ .expecteds
+ .get_many_mut(VALUES)
+ .expect("unable to get all the check-cfg values buckets");
+
+ for target in TARGETS
+ .iter()
+ .map(|target| Target::expect_builtin(&TargetTriple::from_triple(target)))
+ .chain(iter::once(current_target.clone()))
+ {
+ values_target_os.insert(Symbol::intern(&target.options.os));
+ values_target_family.extend(
+ target.options.families.iter().map(|family| Symbol::intern(family)),
+ );
+ values_target_arch.insert(Symbol::intern(&target.arch));
+ values_target_endian.insert(Symbol::intern(target.options.endian.as_str()));
+ values_target_env.insert(Symbol::intern(&target.options.env));
+ values_target_abi.insert(Symbol::intern(&target.options.abi));
+ values_target_vendor.insert(Symbol::intern(&target.options.vendor));
+ values_target_pointer_width.insert(sym::integer(target.pointer_width));
+ }
}
}
}
-
- pub fn fill_well_known(&mut self, current_target: &Target) {
- self.fill_well_known_names();
- self.fill_well_known_values(current_target);
- }
}
pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateConfig {
@@ -1277,7 +1319,7 @@ pub(super) fn build_target_config(
let (target, target_warnings) = target_result.unwrap_or_else(|e| {
early_error(
opts.error_format,
- &format!(
+ format!(
"Error loading target specification: {}. \
Run `rustc --print target-list` for a list of built-in targets",
e
@@ -1285,15 +1327,14 @@ pub(super) fn build_target_config(
)
});
for warning in target_warnings.warning_messages() {
- early_warn(opts.error_format, &warning)
+ early_warn(opts.error_format, warning)
}
if !matches!(target.pointer_width, 16 | 32 | 64) {
early_error(
opts.error_format,
- &format!(
- "target specification was invalid: \
- unrecognized target-pointer-width {}",
+ format!(
+ "target specification was invalid: unrecognized target-pointer-width {}",
target.pointer_width
),
)
@@ -1400,7 +1441,8 @@ The default is {DEFAULT_EDITION} and the latest stable edition is {LATEST_STABLE
pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
vec![
opt::flag_s("h", "help", "Display this message"),
- opt::multi_s("", "cfg", "Configure the compilation environment", "SPEC"),
+ opt::multi_s("", "cfg", "Configure the compilation environment.
+ SPEC supports the syntax `NAME[=\"VALUE\"]`.", "SPEC"),
opt::multi("", "check-cfg", "Provide list of valid cfg options for checking", "SPEC"),
opt::multi_s(
"L",
@@ -1443,7 +1485,7 @@ pub fn rustc_short_optgroups() -> Vec<RustcOptGroup> {
"[crate-name|file-names|sysroot|target-libdir|cfg|calling-conventions|\
target-list|target-cpus|target-features|relocation-models|code-models|\
tls-models|target-spec-json|all-target-specs-json|native-static-libs|\
- stack-protector-strategies|link-args]",
+ stack-protector-strategies|link-args|deployment-target]",
),
opt::flagmulti_s("g", "", "Equivalent to -C debuginfo=2"),
opt::flagmulti_s("O", "", "Equivalent to -C opt-level=2"),
@@ -1556,7 +1598,7 @@ pub fn get_cmd_lint_options(
let lint_cap = matches.opt_str("cap-lints").map(|cap| {
lint::Level::from_str(&cap)
- .unwrap_or_else(|| early_error(error_format, &format!("unknown lint level: `{cap}`")))
+ .unwrap_or_else(|| early_error(error_format, format!("unknown lint level: `{cap}`")))
});
(lint_opts, describe_lints, lint_cap)
@@ -1573,7 +1615,7 @@ pub fn parse_color(matches: &getopts::Matches) -> ColorConfig {
Some(arg) => early_error(
ErrorOutputType::default(),
- &format!(
+ format!(
"argument for `--color` must be auto, \
always or never (instead was `{arg}`)"
),
@@ -1648,7 +1690,7 @@ pub fn parse_json(matches: &getopts::Matches) -> JsonConfig {
"future-incompat" => json_future_incompat = true,
s => early_error(
ErrorOutputType::default(),
- &format!("unknown `--json` option `{s}`"),
+ format!("unknown `--json` option `{s}`"),
),
}
}
@@ -1686,7 +1728,7 @@ pub fn parse_error_format(
Some(arg) => early_error(
ErrorOutputType::HumanReadable(HumanReadableErrorType::Default(color)),
- &format!(
+ format!(
"argument for `--error-format` must be `human`, `json` or \
`short` (instead was `{arg}`)"
),
@@ -1720,7 +1762,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
Some(arg) => Edition::from_str(&arg).unwrap_or_else(|_| {
early_error(
ErrorOutputType::default(),
- &format!(
+ format!(
"argument for `--edition` must be one of: \
{EDITION_NAME_LIST}. (instead was `{arg}`)"
),
@@ -1739,7 +1781,7 @@ pub fn parse_crate_edition(matches: &getopts::Matches) -> Edition {
} else {
format!("edition {edition} is unstable and only available with -Z unstable-options")
};
- early_error(ErrorOutputType::default(), &msg)
+ early_error(ErrorOutputType::default(), msg)
}
edition
@@ -1784,7 +1826,7 @@ fn parse_output_types(
let output_type = OutputType::from_shorthand(shorthand).unwrap_or_else(|| {
early_error(
error_format,
- &format!(
+ format!(
"unknown emission type: `{shorthand}` - expected one of: {display}",
display = OutputType::shorthands_display(),
),
@@ -1823,7 +1865,7 @@ fn should_override_cgus_and_disable_thinlto(
for ot in &incompatible {
early_warn(
error_format,
- &format!(
+ format!(
"`--emit={ot}` with `-o` incompatible with \
`-C codegen-units=N` for N > 1",
),
@@ -1865,7 +1907,7 @@ fn collect_print_requests(
error_format: ErrorOutputType,
) -> Vec<PrintRequest> {
let mut prints = Vec::<PrintRequest>::new();
- if cg.target_cpu.as_ref().map_or(false, |s| s == "help") {
+ if cg.target_cpu.as_ref().is_some_and(|s| s == "help") {
prints.push(PrintRequest::TargetCPUs);
cg.target_cpu = None;
};
@@ -1893,6 +1935,7 @@ fn collect_print_requests(
("all-target-specs-json", PrintRequest::AllTargetSpecs),
("link-args", PrintRequest::LinkArgs),
("split-debuginfo", PrintRequest::SplitDebuginfo),
+ ("deployment-target", PrintRequest::DeploymentTarget),
];
prints.extend(matches.opt_strs("print").into_iter().map(|req| {
@@ -1926,7 +1969,7 @@ fn collect_print_requests(
let prints = prints.join(", ");
early_error(
error_format,
- &format!("unknown print request `{req}`. Valid print requests are: {prints}"),
+ format!("unknown print request `{req}`. Valid print requests are: {prints}"),
);
}
}
@@ -1943,7 +1986,7 @@ pub fn parse_target_triple(
Some(target) if target.ends_with(".json") => {
let path = Path::new(&target);
TargetTriple::from_path(path).unwrap_or_else(|_| {
- early_error(error_format, &format!("target file {path:?} does not exist"))
+ early_error(error_format, format!("target file {path:?} does not exist"))
})
}
Some(target) => TargetTriple::TargetTriple(target),
@@ -1984,7 +2027,7 @@ fn parse_opt_level(
arg => {
early_error(
error_format,
- &format!(
+ format!(
"optimization level needs to be \
between 0-3, s or z (instead was `{arg}`)"
),
@@ -2015,7 +2058,7 @@ pub(crate) fn parse_assert_incr_state(
Some(s) if s.as_str() == "loaded" => Some(IncrementalStateAssertion::Loaded),
Some(s) if s.as_str() == "not-loaded" => Some(IncrementalStateAssertion::NotLoaded),
Some(s) => {
- early_error(error_format, &format!("unexpected incremental state assertion value: {s}"))
+ early_error(error_format, format!("unexpected incremental state assertion value: {s}"))
}
None => None,
}
@@ -2042,13 +2085,13 @@ fn parse_native_lib_kind(
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
- early_error(error_format, &format!("library kind `link-arg` is unstable{why}"))
+ early_error(error_format, format!("library kind `link-arg` is unstable{why}"))
}
NativeLibKind::LinkArg
}
_ => early_error(
error_format,
- &format!(
+ format!(
"unknown library kind `{kind}`, expected one of: static, dylib, framework, link-arg"
),
),
@@ -2083,16 +2126,13 @@ fn parse_native_lib_modifiers(
} else {
", the `-Z unstable-options` flag must also be passed to use it"
};
- early_error(
- error_format,
- &format!("linking modifier `{modifier}` is unstable{why}"),
- )
+ early_error(error_format, format!("linking modifier `{modifier}` is unstable{why}"))
}
};
let assign_modifier = |dst: &mut Option<bool>| {
if dst.is_some() {
let msg = format!("multiple `{modifier}` modifiers in a single `-l` option");
- early_error(error_format, &msg)
+ early_error(error_format, msg)
} else {
*dst = Some(value);
}
@@ -2129,7 +2169,7 @@ fn parse_native_lib_modifiers(
// string, like `modifiers = ""`.
_ => early_error(
error_format,
- &format!(
+ format!(
"unknown linking modifier `{modifier}`, expected one \
of: bundle, verbatim, whole-archive, as-needed"
),
@@ -2235,6 +2275,7 @@ pub fn parse_externs(
let mut is_private_dep = false;
let mut add_prelude = true;
let mut nounused_dep = false;
+ let mut force = false;
if let Some(opts) = options {
if !is_unstable_enabled {
early_error(
@@ -2257,7 +2298,8 @@ pub fn parse_externs(
}
}
"nounused" => nounused_dep = true,
- _ => early_error(error_format, &format!("unknown --extern option `{opt}`")),
+ "force" => force = true,
+ _ => early_error(error_format, format!("unknown --extern option `{opt}`")),
}
}
}
@@ -2267,6 +2309,8 @@ pub fn parse_externs(
entry.is_private_dep |= is_private_dep;
// likewise `nounused`
entry.nounused_dep |= nounused_dep;
+ // and `force`
+ entry.force |= force;
// If any flag is missing `noprelude`, then add to the prelude.
entry.add_prelude |= add_prelude;
}
@@ -2321,7 +2365,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
let unparsed_crate_types = matches.opt_strs("crate-type");
let crate_types = parse_crate_types_from_list(unparsed_crate_types)
- .unwrap_or_else(|e| early_error(error_format, &e));
+ .unwrap_or_else(|e| early_error(error_format, e));
let mut unstable_opts = UnstableOptions::build(matches, error_format);
let (lint_opts, describe_lints, lint_cap) = get_cmd_lint_options(matches, error_format);
@@ -2549,7 +2593,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
};
let working_dir = std::env::current_dir().unwrap_or_else(|e| {
- early_error(error_format, &format!("Current directory is invalid: {e}"));
+ early_error(error_format, format!("Current directory is invalid: {e}"));
});
let remap = FilePathMapping::new(remap_path_prefix.clone());
@@ -2621,7 +2665,7 @@ fn parse_pretty(unstable_opts: &UnstableOptions, efmt: ErrorOutputType) -> Optio
"mir-cfg" => MirCFG,
name => early_error(
efmt,
- &format!(
+ format!(
"argument to `unpretty` must be one of `normal`, `identified`, \
`expanded`, `expanded,identified`, `expanded,hygiene`, \
`ast-tree`, `ast-tree,expanded`, `hir`, `hir,identified`, \
@@ -2699,7 +2743,7 @@ pub mod nightly_options {
if opt.name != "Z" && !has_z_unstable_option {
early_error(
ErrorOutputType::default(),
- &format!(
+ format!(
"the `-Z unstable-options` flag must also be passed to enable \
the flag `{}`",
opt.name
@@ -2712,11 +2756,10 @@ pub mod nightly_options {
match opt.stability {
OptionStability::Unstable => {
let msg = format!(
- "the option `{}` is only accepted on the \
- nightly compiler",
+ "the option `{}` is only accepted on the nightly compiler",
opt.name
);
- early_error(ErrorOutputType::default(), &msg);
+ early_error(ErrorOutputType::default(), msg);
}
OptionStability::Stable => {}
}
diff --git a/compiler/rustc_session/src/cstore.rs b/compiler/rustc_session/src/cstore.rs
index dd1721801..dc475e8c6 100644
--- a/compiler/rustc_session/src/cstore.rs
+++ b/compiler/rustc_session/src/cstore.rs
@@ -6,7 +6,8 @@ use crate::search_paths::PathKind;
use crate::utils::NativeLibKind;
use crate::Session;
use rustc_ast as ast;
-use rustc_data_structures::sync::{self, AppendOnlyIndexVec, MetadataRef, RwLock};
+use rustc_data_structures::owned_slice::OwnedSlice;
+use rustc_data_structures::sync::{self, AppendOnlyIndexVec, RwLock};
use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, StableCrateId, LOCAL_CRATE};
use rustc_hir::definitions::{DefKey, DefPath, DefPathHash, Definitions};
use rustc_span::hygiene::{ExpnHash, ExpnId};
@@ -203,11 +204,11 @@ pub enum ExternCrateSource {
/// metadata in library -- this trait just serves to decouple rustc_metadata from
/// the archive reader, which depends on LLVM.
pub trait MetadataLoader: std::fmt::Debug {
- fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
- fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<MetadataRef, String>;
+ fn get_rlib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
+ fn get_dylib_metadata(&self, target: &Target, filename: &Path) -> Result<OwnedSlice, String>;
}
-pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync;
+pub type MetadataLoaderDyn = dyn MetadataLoader + Send + Sync + sync::DynSend + sync::DynSync;
/// A store of Rust crates, through which their metadata can be accessed.
///
@@ -252,7 +253,7 @@ pub trait CrateStore: std::fmt::Debug {
fn import_source_files(&self, sess: &Session, cnum: CrateNum);
}
-pub type CrateStoreDyn = dyn CrateStore + sync::Sync + sync::Send;
+pub type CrateStoreDyn = dyn CrateStore + sync::DynSync + sync::DynSend;
pub struct Untracked {
pub cstore: RwLock<Box<CrateStoreDyn>>,
diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs
index bd32adbbd..546c0fa8e 100644
--- a/compiler/rustc_session/src/errors.rs
+++ b/compiler/rustc_session/src/errors.rs
@@ -6,7 +6,7 @@ use rustc_ast::token;
use rustc_ast::util::literal::LitError;
use rustc_errors::{error_code, DiagnosticMessage, EmissionGuarantee, IntoDiagnostic, MultiSpan};
use rustc_macros::Diagnostic;
-use rustc_span::{Span, Symbol};
+use rustc_span::{BytePos, Span, Symbol};
use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple};
#[derive(Diagnostic)]
@@ -111,8 +111,24 @@ pub struct CannotMixAndMatchSanitizers {
pub struct CannotEnableCrtStaticLinux;
#[derive(Diagnostic)]
-#[diag(session_sanitizer_cfi_enabled)]
-pub struct SanitizerCfiEnabled;
+#[diag(session_sanitizer_cfi_requires_lto)]
+pub struct SanitizerCfiRequiresLto;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_canonical_jump_tables_requires_cfi)]
+pub struct SanitizerCfiCanonicalJumpTablesRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_generalize_pointers_requires_cfi)]
+pub struct SanitizerCfiGeneralizePointersRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_sanitizer_cfi_normalize_integers_requires_cfi)]
+pub struct SanitizerCfiNormalizeIntegersRequiresCfi;
+
+#[derive(Diagnostic)]
+#[diag(session_split_lto_unit_requires_lto)]
+pub struct SplitLtoUnitRequiresLto;
#[derive(Diagnostic)]
#[diag(session_unstable_virtual_function_elimination)]
@@ -307,6 +323,13 @@ pub(crate) struct BinaryFloatLiteralNotSupported {
pub span: Span,
}
+#[derive(Diagnostic)]
+#[diag(session_nul_in_c_str)]
+pub(crate) struct NulInCStr {
+ #[primary_span]
+ pub span: Span,
+}
+
pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span: Span) {
// Checks if `s` looks like i32 or u1234 etc.
fn looks_like_width_suffix(first_chars: &[char], s: &str) -> bool {
@@ -385,6 +408,12 @@ pub fn report_lit_error(sess: &ParseSess, err: LitError, lit: token::Lit, span:
};
sess.emit_err(IntLiteralTooLarge { span, limit });
}
+ LitError::NulInCStr(range) => {
+ let lo = BytePos(span.lo().0 + range.start as u32 + 2);
+ let hi = BytePos(span.lo().0 + range.end as u32 + 2);
+ let span = span.with_lo(lo).with_hi(hi);
+ sess.emit_err(NulInCStr { span });
+ }
}
}
diff --git a/compiler/rustc_session/src/filesearch.rs b/compiler/rustc_session/src/filesearch.rs
index 7fdbd48d5..3988416d0 100644
--- a/compiler/rustc_session/src/filesearch.rs
+++ b/compiler/rustc_session/src/filesearch.rs
@@ -135,13 +135,13 @@ fn current_dll_path() -> Result<PathBuf, String> {
use windows::{
core::PCWSTR,
- Win32::Foundation::HINSTANCE,
+ Win32::Foundation::HMODULE,
Win32::System::LibraryLoader::{
GetModuleFileNameW, GetModuleHandleExW, GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
},
};
- let mut module = HINSTANCE::default();
+ let mut module = HMODULE::default();
unsafe {
GetModuleHandleExW(
GET_MODULE_HANDLE_EX_FLAG_FROM_ADDRESS,
diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs
index 968728905..590a68c66 100644
--- a/compiler/rustc_session/src/lib.rs
+++ b/compiler/rustc_session/src/lib.rs
@@ -19,7 +19,7 @@ pub mod errors;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
pub mod cgu_reuse_tracker;
pub mod utils;
diff --git a/compiler/rustc_session/src/options.rs b/compiler/rustc_session/src/options.rs
index 631dd0a21..2c4c4a7a6 100644
--- a/compiler/rustc_session/src/options.rs
+++ b/compiler/rustc_session/src/options.rs
@@ -329,21 +329,21 @@ fn build_options<O: Default>(
match value {
None => early_error(
error_format,
- &format!(
+ format!(
"{0} option `{1}` requires {2} ({3} {1}=<value>)",
outputname, key, type_desc, prefix
),
),
Some(value) => early_error(
error_format,
- &format!(
+ format!(
"incorrect value `{value}` for {outputname} option `{key}` - {type_desc} was expected"
),
),
}
}
}
- None => early_error(error_format, &format!("unknown {outputname} option: `{key}`")),
+ None => early_error(error_format, format!("unknown {outputname} option: `{key}`")),
}
}
return op;
@@ -917,7 +917,7 @@ mod parse {
}
}
- let mut options = slot.get_or_insert_default();
+ let options = slot.get_or_insert_default();
let mut seen_always = false;
let mut seen_never = false;
let mut seen_ignore_loops = false;
@@ -1235,6 +1235,8 @@ options! {
line-tables-only, limited, or full; default: 0)"),
default_linker_libraries: bool = (false, parse_bool, [UNTRACKED],
"allow the linker to link its default libraries (default: no)"),
+ dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
+ "import library generation tool (ignored except when targeting windows-gnu)"),
embed_bitcode: bool = (true, parse_bool, [TRACKED],
"emit bitcode in rlibs (default: yes)"),
extra_filename: String = (String::new(), parse_string, [UNTRACKED],
@@ -1391,8 +1393,6 @@ options! {
(default: no)"),
diagnostic_width: Option<usize> = (None, parse_opt_number, [UNTRACKED],
"set the current output width for diagnostic truncation"),
- dlltool: Option<PathBuf> = (None, parse_opt_pathbuf, [UNTRACKED],
- "import library generation tool (windows-gnu only)"),
dont_buffer_diagnostics: bool = (false, parse_bool, [UNTRACKED],
"emit diagnostics rather than buffering (breaks NLL error downgrading, sorting) \
(default: no)"),
@@ -1452,9 +1452,9 @@ options! {
fewer_names: Option<bool> = (None, parse_opt_bool, [TRACKED],
"reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \
(default: no)"),
- flatten_format_args: bool = (false, parse_bool, [TRACKED],
+ flatten_format_args: bool = (true, parse_bool, [TRACKED],
"flatten nested format_args!() and literals into a simplified format_args!() call \
- (default: no)"),
+ (default: yes)"),
force_unstable_if_unmarked: bool = (false, parse_bool, [TRACKED],
"force all crates to be `rustc_private` unstable (default: no)"),
fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED],
@@ -1555,9 +1555,12 @@ options! {
"emit Retagging MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
(default: no)"),
mir_enable_passes: Vec<(String, bool)> = (Vec::new(), parse_list_with_polarity, [TRACKED],
- "use like `-Zmir-enable-passes=+DestProp,-InstCombine`. Forces the specified passes to be \
+ "use like `-Zmir-enable-passes=+DestinationPropagation,-InstSimplify`. Forces the specified passes to be \
enabled, overriding all other checks. Passes that are not specified are enabled or \
disabled by other flags as usual."),
+ mir_keep_place_mention: bool = (false, parse_bool, [TRACKED],
+ "keep place mention MIR statements, interpreted e.g., by miri; implies -Zmir-opt-level=0 \
+ (default: no)"),
#[rustc_lint_opt_deny_field_access("use `Session::mir_opt_level` instead of this field")]
mir_opt_level: Option<usize> = (None, parse_opt_number, [TRACKED],
"MIR optimization level (0-4; default: 1 in non optimized builds and 2 in optimized builds)"),
@@ -1659,6 +1662,12 @@ options! {
"immediately print bugs registered with `delay_span_bug` (default: no)"),
sanitizer: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
"use a sanitizer"),
+ sanitizer_cfi_canonical_jump_tables: Option<bool> = (Some(true), parse_opt_bool, [TRACKED],
+ "enable canonical jump tables (default: yes)"),
+ sanitizer_cfi_generalize_pointers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable generalizing pointer types (default: no)"),
+ sanitizer_cfi_normalize_integers: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable normalizing integer types (default: no)"),
sanitizer_memory_track_origins: usize = (0, parse_sanitizer_memory_track_origins, [TRACKED],
"enable origins tracking in MemorySanitizer"),
sanitizer_recover: SanitizerSet = (SanitizerSet::empty(), parse_sanitizers, [TRACKED],
@@ -1704,11 +1713,17 @@ options! {
file which is ignored by the linker
`single`: sections which do not require relocation are written into object file but ignored
by the linker"),
+ split_lto_unit: Option<bool> = (None, parse_opt_bool, [TRACKED],
+ "enable LTO unit splitting (default: no)"),
src_hash_algorithm: Option<SourceFileHashAlgorithm> = (None, parse_src_file_hash, [TRACKED],
"hash algorithm of source files in debug info (`md5`, `sha1`, or `sha256`)"),
#[rustc_lint_opt_deny_field_access("use `Session::stack_protector` instead of this field")]
stack_protector: StackProtector = (StackProtector::None, parse_stack_protector, [TRACKED],
"control stack smash protection strategy (`rustc --print stack-protector-strategies` for details)"),
+ staticlib_allow_rdylib_deps: bool = (false, parse_bool, [TRACKED],
+ "allow staticlibs to have rust dylib dependencies"),
+ staticlib_prefer_dynamic: bool = (false, parse_bool, [TRACKED],
+ "prefer dynamic linking to static linking for staticlibs (default: no)"),
strict_init_checks: bool = (false, parse_bool, [TRACKED],
"control if mem::uninitialized and mem::zeroed panic on more UB"),
strip: Strip = (Strip::None, parse_strip, [UNTRACKED],
diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs
index 15e27952c..7b396dde9 100644
--- a/compiler/rustc_session/src/parse.rs
+++ b/compiler/rustc_session/src/parse.rs
@@ -214,8 +214,6 @@ pub struct ParseSess {
pub env_depinfo: Lock<FxHashSet<(Symbol, Option<Symbol>)>>,
/// File paths accessed during the build.
pub file_depinfo: Lock<FxHashSet<Symbol>>,
- /// All the type ascriptions expressions that have had a suggestion for likely path typo.
- pub type_ascription_path_suggestions: Lock<FxHashSet<Span>>,
/// Whether cfg(version) should treat the current release as incomplete
pub assume_incomplete_release: bool,
/// Spans passed to `proc_macro::quote_span`. Each span has a numerical
@@ -258,7 +256,6 @@ impl ParseSess {
reached_eof: AtomicBool::new(false),
env_depinfo: Default::default(),
file_depinfo: Default::default(),
- type_ascription_path_suggestions: Default::default(),
assume_incomplete_release: false,
proc_macro_quoted_spans: Default::default(),
attr_id_generator: AttrIdGenerator::new(),
@@ -292,7 +289,7 @@ impl ParseSess {
lint: &'static Lint,
span: impl Into<MultiSpan>,
node_id: NodeId,
- msg: &str,
+ msg: impl Into<DiagnosticMessage>,
) {
self.buffered_lints.with_lock(|buffered_lints| {
buffered_lints.push(BufferedEarlyLint {
@@ -310,7 +307,7 @@ impl ParseSess {
lint: &'static Lint,
span: impl Into<MultiSpan>,
node_id: NodeId,
- msg: &str,
+ msg: impl Into<DiagnosticMessage>,
diagnostic: BuiltinLintDiagnostics,
) {
self.buffered_lints.with_lock(|buffered_lints| {
diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs
index 340bb158e..bbe52dbce 100644
--- a/compiler/rustc_session/src/session.rs
+++ b/compiler/rustc_session/src/session.rs
@@ -211,6 +211,9 @@ pub struct Session {
/// Set of enabled features for the current target, including unstable ones.
pub unstable_target_features: FxIndexSet<Symbol>,
+
+ /// The version of the rustc process, possibly including a commit hash and description.
+ pub cfg_version: &'static str,
}
pub struct PerfStats {
@@ -490,20 +493,6 @@ impl Session {
}
#[rustc_lint_diagnostics]
#[track_caller]
- pub fn span_err_or_warn<S: Into<MultiSpan>>(
- &self,
- is_warning: bool,
- sp: S,
- msg: impl Into<DiagnosticMessage>,
- ) {
- if is_warning {
- self.span_warn(sp, msg);
- } else {
- self.span_err(sp, msg);
- }
- }
- #[rustc_lint_diagnostics]
- #[track_caller]
pub fn span_err<S: Into<MultiSpan>>(
&self,
sp: S,
@@ -766,10 +755,30 @@ impl Session {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::CFI)
}
+ pub fn is_sanitizer_cfi_canonical_jump_tables_disabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(false)
+ }
+
+ pub fn is_sanitizer_cfi_canonical_jump_tables_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_canonical_jump_tables == Some(true)
+ }
+
+ pub fn is_sanitizer_cfi_generalize_pointers_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_generalize_pointers == Some(true)
+ }
+
+ pub fn is_sanitizer_cfi_normalize_integers_enabled(&self) -> bool {
+ self.opts.unstable_opts.sanitizer_cfi_normalize_integers == Some(true)
+ }
+
pub fn is_sanitizer_kcfi_enabled(&self) -> bool {
self.opts.unstable_opts.sanitizer.contains(SanitizerSet::KCFI)
}
+ pub fn is_split_lto_unit_enabled(&self) -> bool {
+ self.opts.unstable_opts.split_lto_unit == Some(true)
+ }
+
/// Check whether this compile session and crate type use static crt.
pub fn crt_static(&self, crate_type: Option<CrateType>) -> bool {
if !self.target.crt_static_respected {
@@ -811,7 +820,7 @@ impl Session {
}
pub fn generate_proc_macro_decls_symbol(&self, stable_crate_id: StableCrateId) -> String {
- format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.to_u64())
+ format!("__rustc_proc_macro_decls_{:08x}__", stable_crate_id.as_u64())
}
pub fn target_filesearch(&self, kind: PathKind) -> filesearch::FileSearch<'_> {
@@ -1190,6 +1199,7 @@ impl Session {
/// Returns the number of query threads that should be used for this
/// compilation
+ #[inline]
pub fn threads(&self) -> usize {
self.opts.unstable_opts.threads
}
@@ -1359,6 +1369,7 @@ pub fn build_session(
driver_lint_caps: FxHashMap<lint::LintId, lint::Level>,
file_loader: Option<Box<dyn FileLoader + Send + Sync + 'static>>,
target_override: Option<Target>,
+ cfg_version: &'static str,
) -> Session {
// FIXME: This is not general enough to make the warning lint completely override
// normal diagnostic warnings, since the warning lint can also be denied and changed
@@ -1367,8 +1378,8 @@ pub fn build_session(
.lint_opts
.iter()
.rfind(|&(key, _)| *key == "warnings")
- .map_or(false, |&(_, level)| level == lint::Allow);
- let cap_lints_allow = sopts.lint_cap.map_or(false, |cap| cap == lint::Allow);
+ .is_some_and(|&(_, level)| level == lint::Allow);
+ let cap_lints_allow = sopts.lint_cap.is_some_and(|cap| cap == lint::Allow);
let can_emit_warnings = !(warnings_allow || cap_lints_allow);
let sysroot = match &sopts.maybe_sysroot {
@@ -1379,10 +1390,10 @@ pub fn build_session(
let target_cfg = config::build_target_config(&sopts, target_override, &sysroot);
let host_triple = TargetTriple::from_triple(config::host_triple());
let (host, target_warnings) = Target::search(&host_triple, &sysroot).unwrap_or_else(|e| {
- early_error(sopts.error_format, &format!("Error loading host specification: {e}"))
+ early_error(sopts.error_format, format!("Error loading host specification: {e}"))
});
for warning in target_warnings.warning_messages() {
- early_warn(sopts.error_format, &warning)
+ early_warn(sopts.error_format, warning)
}
let loader = file_loader.unwrap_or_else(|| Box::new(RealFileLoader));
@@ -1424,7 +1435,7 @@ pub fn build_session(
match profiler {
Ok(profiler) => Some(Arc::new(profiler)),
Err(e) => {
- early_warn(sopts.error_format, &format!("failed to create profiler: {e}"));
+ early_warn(sopts.error_format, format!("failed to create profiler: {e}"));
None
}
}
@@ -1503,6 +1514,7 @@ pub fn build_session(
asm_arch,
target_features: Default::default(),
unstable_target_features: Default::default(),
+ cfg_version,
};
validate_commandline_args_with_session_available(&sess);
@@ -1581,17 +1593,16 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
sess.emit_err(errors::CannotEnableCrtStaticLinux);
}
- // LLVM CFI and VFE both require LTO.
- if sess.lto() != config::Lto::Fat {
- if sess.is_sanitizer_cfi_enabled() {
- sess.emit_err(errors::SanitizerCfiEnabled);
- }
- if sess.opts.unstable_opts.virtual_function_elimination {
- sess.emit_err(errors::UnstableVirtualFunctionElimination);
- }
+ // LLVM CFI requires LTO.
+ if sess.is_sanitizer_cfi_enabled()
+ && !(sess.lto() == config::Lto::Fat
+ || sess.lto() == config::Lto::Thin
+ || sess.opts.cg.linker_plugin_lto.enabled())
+ {
+ sess.emit_err(errors::SanitizerCfiRequiresLto);
}
- // LLVM CFI and KCFI are mutually exclusive
+ // LLVM CFI is incompatible with LLVM KCFI.
if sess.is_sanitizer_cfi_enabled() && sess.is_sanitizer_kcfi_enabled() {
sess.emit_err(errors::CannotMixAndMatchSanitizers {
first: "cfi".to_string(),
@@ -1599,6 +1610,43 @@ fn validate_commandline_args_with_session_available(sess: &Session) {
});
}
+ // Canonical jump tables requires CFI.
+ if sess.is_sanitizer_cfi_canonical_jump_tables_disabled() {
+ if !sess.is_sanitizer_cfi_enabled() {
+ sess.emit_err(errors::SanitizerCfiCanonicalJumpTablesRequiresCfi);
+ }
+ }
+
+ // LLVM CFI pointer generalization requires CFI or KCFI.
+ if sess.is_sanitizer_cfi_generalize_pointers_enabled() {
+ if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
+ sess.emit_err(errors::SanitizerCfiGeneralizePointersRequiresCfi);
+ }
+ }
+
+ // LLVM CFI integer normalization requires CFI or KCFI.
+ if sess.is_sanitizer_cfi_normalize_integers_enabled() {
+ if !(sess.is_sanitizer_cfi_enabled() || sess.is_sanitizer_kcfi_enabled()) {
+ sess.emit_err(errors::SanitizerCfiNormalizeIntegersRequiresCfi);
+ }
+ }
+
+ // LTO unit splitting requires LTO.
+ if sess.is_split_lto_unit_enabled()
+ && !(sess.lto() == config::Lto::Fat
+ || sess.lto() == config::Lto::Thin
+ || sess.opts.cg.linker_plugin_lto.enabled())
+ {
+ sess.emit_err(errors::SplitLtoUnitRequiresLto);
+ }
+
+ // VFE requires LTO.
+ if sess.lto() != config::Lto::Fat {
+ if sess.opts.unstable_opts.virtual_function_elimination {
+ sess.emit_err(errors::UnstableVirtualFunctionElimination);
+ }
+ }
+
if sess.opts.unstable_opts.stack_protector != StackProtector::None {
if !sess.target.options.supports_stack_protector {
sess.emit_warning(errors::StackProtectorNotSupportedForTarget {
@@ -1684,18 +1732,22 @@ fn early_error_handler(output: config::ErrorOutputType) -> rustc_errors::Handler
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error_no_abort(output: config::ErrorOutputType, msg: &str) -> ErrorGuaranteed {
+#[must_use = "ErrorGuaranteed must be returned from `run_compiler` in order to exit with a non-zero status code"]
+pub fn early_error_no_abort(
+ output: config::ErrorOutputType,
+ msg: impl Into<DiagnosticMessage>,
+) -> ErrorGuaranteed {
early_error_handler(output).struct_err(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_error(output: config::ErrorOutputType, msg: &str) -> ! {
+pub fn early_error(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) -> ! {
early_error_handler(output).struct_fatal(msg).emit()
}
#[allow(rustc::untranslatable_diagnostic)]
#[allow(rustc::diagnostic_outside_of_impl)]
-pub fn early_warn(output: config::ErrorOutputType, msg: &str) {
+pub fn early_warn(output: config::ErrorOutputType, msg: impl Into<DiagnosticMessage>) {
early_error_handler(output).struct_warn(msg).emit()
}
diff --git a/compiler/rustc_smir/Cargo.toml b/compiler/rustc_smir/Cargo.toml
index fb97ee5be..80360a3c7 100644
--- a/compiler/rustc_smir/Cargo.toml
+++ b/compiler/rustc_smir/Cargo.toml
@@ -4,6 +4,7 @@ version = "0.0.0"
edition = "2021"
[dependencies]
+rustc_hir = { path = "../rustc_hir" }
rustc_middle = { path = "../rustc_middle", optional = true }
rustc_span = { path = "../rustc_span", optional = true }
tracing = "0.1"
diff --git a/compiler/rustc_smir/src/lib.rs b/compiler/rustc_smir/src/lib.rs
index 54d474db0..b00f0a1c1 100644
--- a/compiler/rustc_smir/src/lib.rs
+++ b/compiler/rustc_smir/src/lib.rs
@@ -11,6 +11,8 @@
test(attr(allow(unused_variables), deny(warnings)))
)]
#![cfg_attr(not(feature = "default"), feature(rustc_private))]
+#![feature(local_key_cell_methods)]
+#![feature(ptr_metadata)]
pub mod rustc_internal;
pub mod stable_mir;
diff --git a/compiler/rustc_smir/src/rustc_internal/mod.rs b/compiler/rustc_smir/src/rustc_internal/mod.rs
index 5998c8b65..609a04d26 100644
--- a/compiler/rustc_smir/src/rustc_internal/mod.rs
+++ b/compiler/rustc_smir/src/rustc_internal/mod.rs
@@ -3,30 +3,49 @@
//! For that, we define APIs that will temporarily be public to 3P that exposes rustc internal APIs
//! until stable MIR is complete.
-use std::sync::RwLock;
-
-use crate::stable_mir;
+use crate::{
+ rustc_smir::Tables,
+ stable_mir::{self, with},
+};
+use rustc_middle::ty::TyCtxt;
pub use rustc_span::def_id::{CrateNum, DefId};
-static DEF_ID_MAP: RwLock<Vec<DefId>> = RwLock::new(Vec::new());
+fn with_tables<R>(mut f: impl FnMut(&mut Tables<'_>) -> R) -> R {
+ let mut ret = None;
+ with(|tables| tables.rustc_tables(&mut |t| ret = Some(f(t))));
+ ret.unwrap()
+}
pub fn item_def_id(item: &stable_mir::CrateItem) -> DefId {
- DEF_ID_MAP.read().unwrap()[item.0]
+ with_tables(|t| t.item_def_id(item))
}
pub fn crate_item(did: DefId) -> stable_mir::CrateItem {
- // FIXME: this becomes inefficient when we have too many ids
- let mut map = DEF_ID_MAP.write().unwrap();
- for (i, &d) in map.iter().enumerate() {
- if d == did {
- return stable_mir::CrateItem(i);
+ with_tables(|t| t.crate_item(did))
+}
+
+impl<'tcx> Tables<'tcx> {
+ pub fn item_def_id(&self, item: &stable_mir::CrateItem) -> DefId {
+ self.def_ids[item.0]
+ }
+
+ pub fn crate_item(&mut self, did: DefId) -> stable_mir::CrateItem {
+ // FIXME: this becomes inefficient when we have too many ids
+ for (i, &d) in self.def_ids.iter().enumerate() {
+ if d == did {
+ return stable_mir::CrateItem(i);
+ }
}
+ let id = self.def_ids.len();
+ self.def_ids.push(did);
+ stable_mir::CrateItem(id)
}
- let id = map.len();
- map.push(did);
- stable_mir::CrateItem(id)
}
pub fn crate_num(item: &stable_mir::Crate) -> CrateNum {
item.id.into()
}
+
+pub fn run(tcx: TyCtxt<'_>, f: impl FnOnce()) {
+ crate::stable_mir::run(Tables { tcx, def_ids: vec![], types: vec![] }, f);
+}
diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs
index 4dad3c6bc..5572108f4 100644
--- a/compiler/rustc_smir/src/rustc_smir/mod.rs
+++ b/compiler/rustc_smir/src/rustc_smir/mod.rs
@@ -7,41 +7,107 @@
//!
//! For now, we are developing everything inside `rustc`, thus, we keep this module private.
-use crate::{
- rustc_internal::{crate_item, item_def_id},
- stable_mir::{self},
-};
-use rustc_middle::ty::{tls::with, TyCtxt};
-use rustc_span::def_id::{CrateNum, LOCAL_CRATE};
+use crate::stable_mir::{self, ty::TyKind, Context};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_span::def_id::{CrateNum, DefId, LOCAL_CRATE};
use tracing::debug;
-/// Get information about the local crate.
-pub fn local_crate() -> stable_mir::Crate {
- with(|tcx| smir_crate(tcx, LOCAL_CRATE))
-}
+impl<'tcx> Context for Tables<'tcx> {
+ fn local_crate(&self) -> stable_mir::Crate {
+ smir_crate(self.tcx, LOCAL_CRATE)
+ }
-/// Retrieve a list of all external crates.
-pub fn external_crates() -> Vec<stable_mir::Crate> {
- with(|tcx| tcx.crates(()).iter().map(|crate_num| smir_crate(tcx, *crate_num)).collect())
-}
+ fn external_crates(&self) -> Vec<stable_mir::Crate> {
+ self.tcx.crates(()).iter().map(|crate_num| smir_crate(self.tcx, *crate_num)).collect()
+ }
-/// Find a crate with the given name.
-pub fn find_crate(name: &str) -> Option<stable_mir::Crate> {
- with(|tcx| {
- [LOCAL_CRATE].iter().chain(tcx.crates(()).iter()).find_map(|crate_num| {
- let crate_name = tcx.crate_name(*crate_num).to_string();
- (name == crate_name).then(|| smir_crate(tcx, *crate_num))
+ fn find_crate(&self, name: &str) -> Option<stable_mir::Crate> {
+ [LOCAL_CRATE].iter().chain(self.tcx.crates(()).iter()).find_map(|crate_num| {
+ let crate_name = self.tcx.crate_name(*crate_num).to_string();
+ (name == crate_name).then(|| smir_crate(self.tcx, *crate_num))
})
- })
+ }
+
+ fn all_local_items(&mut self) -> stable_mir::CrateItems {
+ self.tcx.mir_keys(()).iter().map(|item| self.crate_item(item.to_def_id())).collect()
+ }
+ fn entry_fn(&mut self) -> Option<stable_mir::CrateItem> {
+ Some(self.crate_item(self.tcx.entry_fn(())?.0))
+ }
+ fn mir_body(&mut self, item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
+ let def_id = self.item_def_id(item);
+ let mir = self.tcx.optimized_mir(def_id);
+ stable_mir::mir::Body {
+ blocks: mir
+ .basic_blocks
+ .iter()
+ .map(|block| stable_mir::mir::BasicBlock {
+ terminator: rustc_terminator_to_terminator(block.terminator()),
+ statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
+ })
+ .collect(),
+ locals: mir.local_decls.iter().map(|decl| self.intern_ty(decl.ty)).collect(),
+ }
+ }
+
+ fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>)) {
+ f(self)
+ }
+
+ fn ty_kind(&mut self, ty: crate::stable_mir::ty::Ty) -> TyKind {
+ self.rustc_ty_to_ty(self.types[ty.0])
+ }
}
-/// Retrieve all items of the local crate that have a MIR associated with them.
-pub fn all_local_items() -> stable_mir::CrateItems {
- with(|tcx| tcx.mir_keys(()).iter().map(|item| crate_item(item.to_def_id())).collect())
+pub struct Tables<'tcx> {
+ pub tcx: TyCtxt<'tcx>,
+ pub def_ids: Vec<DefId>,
+ pub types: Vec<Ty<'tcx>>,
}
-pub fn entry_fn() -> Option<stable_mir::CrateItem> {
- with(|tcx| Some(crate_item(tcx.entry_fn(())?.0)))
+impl<'tcx> Tables<'tcx> {
+ fn rustc_ty_to_ty(&mut self, ty: Ty<'tcx>) -> TyKind {
+ match ty.kind() {
+ ty::Bool => TyKind::Bool,
+ ty::Char => todo!(),
+ ty::Int(_) => todo!(),
+ ty::Uint(_) => todo!(),
+ ty::Float(_) => todo!(),
+ ty::Adt(_, _) => todo!(),
+ ty::Foreign(_) => todo!(),
+ ty::Str => todo!(),
+ ty::Array(_, _) => todo!(),
+ ty::Slice(_) => todo!(),
+ ty::RawPtr(_) => todo!(),
+ ty::Ref(_, _, _) => todo!(),
+ ty::FnDef(_, _) => todo!(),
+ ty::FnPtr(_) => todo!(),
+ ty::Placeholder(..) => todo!(),
+ ty::Dynamic(_, _, _) => todo!(),
+ ty::Closure(_, _) => todo!(),
+ ty::Generator(_, _, _) => todo!(),
+ ty::GeneratorWitness(_) => todo!(),
+ ty::GeneratorWitnessMIR(_, _) => todo!(),
+ ty::Never => todo!(),
+ ty::Tuple(fields) => {
+ TyKind::Tuple(fields.iter().map(|ty| self.intern_ty(ty)).collect())
+ }
+ ty::Alias(_, _) => todo!(),
+ ty::Param(_) => todo!(),
+ ty::Bound(_, _) => todo!(),
+ ty::Infer(_) => todo!(),
+ ty::Error(_) => todo!(),
+ }
+ }
+
+ fn intern_ty(&mut self, ty: Ty<'tcx>) -> stable_mir::ty::Ty {
+ if let Some(id) = self.types.iter().position(|&t| t == ty) {
+ return stable_mir::ty::Ty(id);
+ }
+ let id = self.types.len();
+ self.types.push(ty);
+ stable_mir::ty::Ty(id)
+ }
}
/// Build a stable mir crate from a given crate number.
@@ -52,23 +118,6 @@ fn smir_crate(tcx: TyCtxt<'_>, crate_num: CrateNum) -> stable_mir::Crate {
stable_mir::Crate { id: crate_num.into(), name: crate_name, is_local }
}
-pub fn mir_body(item: &stable_mir::CrateItem) -> stable_mir::mir::Body {
- with(|tcx| {
- let def_id = item_def_id(item);
- let mir = tcx.optimized_mir(def_id);
- stable_mir::mir::Body {
- blocks: mir
- .basic_blocks
- .iter()
- .map(|block| stable_mir::mir::BasicBlock {
- terminator: rustc_terminator_to_terminator(block.terminator()),
- statements: block.statements.iter().map(rustc_statement_to_statement).collect(),
- })
- .collect(),
- }
- })
-}
-
fn rustc_statement_to_statement(
s: &rustc_middle::mir::Statement<'_>,
) -> stable_mir::mir::Statement {
@@ -93,10 +142,10 @@ fn rustc_statement_to_statement(
}
}
-fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Operand {
+fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir::mir::Rvalue {
use rustc_middle::mir::Rvalue::*;
match rvalue {
- Use(op) => rustc_op_to_op(op),
+ Use(op) => stable_mir::mir::Rvalue::Use(rustc_op_to_op(op)),
Repeat(_, _) => todo!(),
Ref(_, _, _) => todo!(),
ThreadLocalRef(_) => todo!(),
@@ -104,9 +153,15 @@ fn rustc_rvalue_to_rvalue(rvalue: &rustc_middle::mir::Rvalue<'_>) -> stable_mir:
Len(_) => todo!(),
Cast(_, _, _) => todo!(),
BinaryOp(_, _) => todo!(),
- CheckedBinaryOp(_, _) => todo!(),
+ CheckedBinaryOp(bin_op, ops) => stable_mir::mir::Rvalue::CheckedBinaryOp(
+ rustc_bin_op_to_bin_op(bin_op),
+ rustc_op_to_op(&ops.0),
+ rustc_op_to_op(&ops.1),
+ ),
NullaryOp(_, _) => todo!(),
- UnaryOp(_, _) => todo!(),
+ UnaryOp(un_op, op) => {
+ stable_mir::mir::Rvalue::UnaryOp(rustc_un_op_to_un_op(un_op), rustc_op_to_op(op))
+ }
Discriminant(_) => todo!(),
Aggregate(_, _) => todo!(),
ShallowInitBox(_, _) => todo!(),
@@ -124,8 +179,112 @@ fn rustc_op_to_op(op: &rustc_middle::mir::Operand<'_>) -> stable_mir::mir::Opera
}
fn rustc_place_to_place(place: &rustc_middle::mir::Place<'_>) -> stable_mir::mir::Place {
- assert_eq!(&place.projection[..], &[]);
- stable_mir::mir::Place { local: place.local.as_usize() }
+ stable_mir::mir::Place {
+ local: place.local.as_usize(),
+ projection: format!("{:?}", place.projection),
+ }
+}
+
+fn rustc_unwind_to_unwind(
+ unwind: &rustc_middle::mir::UnwindAction,
+) -> stable_mir::mir::UnwindAction {
+ use rustc_middle::mir::UnwindAction;
+ match unwind {
+ UnwindAction::Continue => stable_mir::mir::UnwindAction::Continue,
+ UnwindAction::Unreachable => stable_mir::mir::UnwindAction::Unreachable,
+ UnwindAction::Terminate => stable_mir::mir::UnwindAction::Terminate,
+ UnwindAction::Cleanup(bb) => stable_mir::mir::UnwindAction::Cleanup(bb.as_usize()),
+ }
+}
+
+fn rustc_assert_msg_to_msg<'tcx>(
+ assert_message: &rustc_middle::mir::AssertMessage<'tcx>,
+) -> stable_mir::mir::AssertMessage {
+ use rustc_middle::mir::AssertKind;
+ match assert_message {
+ AssertKind::BoundsCheck { len, index } => stable_mir::mir::AssertMessage::BoundsCheck {
+ len: rustc_op_to_op(len),
+ index: rustc_op_to_op(index),
+ },
+ AssertKind::Overflow(bin_op, op1, op2) => stable_mir::mir::AssertMessage::Overflow(
+ rustc_bin_op_to_bin_op(bin_op),
+ rustc_op_to_op(op1),
+ rustc_op_to_op(op2),
+ ),
+ AssertKind::OverflowNeg(op) => {
+ stable_mir::mir::AssertMessage::OverflowNeg(rustc_op_to_op(op))
+ }
+ AssertKind::DivisionByZero(op) => {
+ stable_mir::mir::AssertMessage::DivisionByZero(rustc_op_to_op(op))
+ }
+ AssertKind::RemainderByZero(op) => {
+ stable_mir::mir::AssertMessage::RemainderByZero(rustc_op_to_op(op))
+ }
+ AssertKind::ResumedAfterReturn(generator) => {
+ stable_mir::mir::AssertMessage::ResumedAfterReturn(rustc_generator_to_generator(
+ generator,
+ ))
+ }
+ AssertKind::ResumedAfterPanic(generator) => {
+ stable_mir::mir::AssertMessage::ResumedAfterPanic(rustc_generator_to_generator(
+ generator,
+ ))
+ }
+ AssertKind::MisalignedPointerDereference { required, found } => {
+ stable_mir::mir::AssertMessage::MisalignedPointerDereference {
+ required: rustc_op_to_op(required),
+ found: rustc_op_to_op(found),
+ }
+ }
+ }
+}
+
+fn rustc_bin_op_to_bin_op(bin_op: &rustc_middle::mir::BinOp) -> stable_mir::mir::BinOp {
+ use rustc_middle::mir::BinOp;
+ match bin_op {
+ BinOp::Add => stable_mir::mir::BinOp::Add,
+ BinOp::Sub => stable_mir::mir::BinOp::Sub,
+ BinOp::Mul => stable_mir::mir::BinOp::Mul,
+ BinOp::Div => stable_mir::mir::BinOp::Div,
+ BinOp::Rem => stable_mir::mir::BinOp::Rem,
+ BinOp::BitXor => stable_mir::mir::BinOp::BitXor,
+ BinOp::BitAnd => stable_mir::mir::BinOp::BitAnd,
+ BinOp::BitOr => stable_mir::mir::BinOp::BitOr,
+ BinOp::Shl => stable_mir::mir::BinOp::Shl,
+ BinOp::Shr => stable_mir::mir::BinOp::Shr,
+ BinOp::Eq => stable_mir::mir::BinOp::Eq,
+ BinOp::Lt => stable_mir::mir::BinOp::Lt,
+ BinOp::Le => stable_mir::mir::BinOp::Le,
+ BinOp::Ne => stable_mir::mir::BinOp::Ne,
+ BinOp::Ge => stable_mir::mir::BinOp::Ge,
+ BinOp::Gt => stable_mir::mir::BinOp::Gt,
+ BinOp::Offset => stable_mir::mir::BinOp::Offset,
+ }
+}
+
+fn rustc_un_op_to_un_op(unary_op: &rustc_middle::mir::UnOp) -> stable_mir::mir::UnOp {
+ use rustc_middle::mir::UnOp;
+ match unary_op {
+ UnOp::Not => stable_mir::mir::UnOp::Not,
+ UnOp::Neg => stable_mir::mir::UnOp::Neg,
+ }
+}
+
+fn rustc_generator_to_generator(
+ generator: &rustc_hir::GeneratorKind,
+) -> stable_mir::mir::GeneratorKind {
+ use rustc_hir::{AsyncGeneratorKind, GeneratorKind};
+ match generator {
+ GeneratorKind::Async(async_gen) => {
+ let async_gen = match async_gen {
+ AsyncGeneratorKind::Block => stable_mir::mir::AsyncGeneratorKind::Block,
+ AsyncGeneratorKind::Closure => stable_mir::mir::AsyncGeneratorKind::Closure,
+ AsyncGeneratorKind::Fn => stable_mir::mir::AsyncGeneratorKind::Fn,
+ };
+ stable_mir::mir::GeneratorKind::Async(async_gen)
+ }
+ GeneratorKind::Gen => stable_mir::mir::GeneratorKind::Gen,
+ }
}
fn rustc_terminator_to_terminator(
@@ -150,11 +309,29 @@ fn rustc_terminator_to_terminator(
Terminate => Terminator::Abort,
Return => Terminator::Return,
Unreachable => Terminator::Unreachable,
- Drop { .. } => todo!(),
- Call { .. } => todo!(),
- Assert { .. } => todo!(),
+ Drop { place, target, unwind, replace: _ } => Terminator::Drop {
+ place: rustc_place_to_place(place),
+ target: target.as_usize(),
+ unwind: rustc_unwind_to_unwind(unwind),
+ },
+ Call { func, args, destination, target, unwind, from_hir_call: _, fn_span: _ } => {
+ Terminator::Call {
+ func: rustc_op_to_op(func),
+ args: args.iter().map(|arg| rustc_op_to_op(arg)).collect(),
+ destination: rustc_place_to_place(destination),
+ target: target.map(|t| t.as_usize()),
+ unwind: rustc_unwind_to_unwind(unwind),
+ }
+ }
+ Assert { cond, expected, msg, target, unwind } => Terminator::Assert {
+ cond: rustc_op_to_op(cond),
+ expected: *expected,
+ msg: rustc_assert_msg_to_msg(msg),
+ target: target.as_usize(),
+ unwind: rustc_unwind_to_unwind(unwind),
+ },
Yield { .. } => todo!(),
- GeneratorDrop => todo!(),
+ GeneratorDrop => Terminator::GeneratorDrop,
FalseEdge { .. } => todo!(),
FalseUnwind { .. } => todo!(),
InlineAsm { .. } => todo!(),
diff --git a/compiler/rustc_smir/src/stable_mir/mir/body.rs b/compiler/rustc_smir/src/stable_mir/mir/body.rs
index c504065c9..6328c35aa 100644
--- a/compiler/rustc_smir/src/stable_mir/mir/body.rs
+++ b/compiler/rustc_smir/src/stable_mir/mir/body.rs
@@ -1,6 +1,9 @@
+use crate::stable_mir::ty::Ty;
+
#[derive(Clone, Debug)]
pub struct Body {
pub blocks: Vec<BasicBlock>,
+ pub locals: Vec<Ty>,
}
#[derive(Clone, Debug)]
@@ -26,30 +29,99 @@ pub enum Terminator {
Drop {
place: Place,
target: usize,
- unwind: Option<usize>,
+ unwind: UnwindAction,
},
Call {
func: Operand,
args: Vec<Operand>,
destination: Place,
target: Option<usize>,
- cleanup: Option<usize>,
+ unwind: UnwindAction,
},
Assert {
cond: Operand,
expected: bool,
- msg: String,
+ msg: AssertMessage,
target: usize,
- cleanup: Option<usize>,
+ unwind: UnwindAction,
},
+ GeneratorDrop,
+}
+
+#[derive(Clone, Debug)]
+pub enum UnwindAction {
+ Continue,
+ Unreachable,
+ Terminate,
+ Cleanup(usize),
+}
+
+#[derive(Clone, Debug)]
+pub enum AssertMessage {
+ BoundsCheck { len: Operand, index: Operand },
+ Overflow(BinOp, Operand, Operand),
+ OverflowNeg(Operand),
+ DivisionByZero(Operand),
+ RemainderByZero(Operand),
+ ResumedAfterReturn(GeneratorKind),
+ ResumedAfterPanic(GeneratorKind),
+ MisalignedPointerDereference { required: Operand, found: Operand },
+}
+
+#[derive(Clone, Debug)]
+pub enum BinOp {
+ Add,
+ Sub,
+ Mul,
+ Div,
+ Rem,
+ BitXor,
+ BitAnd,
+ BitOr,
+ Shl,
+ Shr,
+ Eq,
+ Lt,
+ Le,
+ Ne,
+ Ge,
+ Gt,
+ Offset,
+}
+
+#[derive(Clone, Debug)]
+pub enum UnOp {
+ Not,
+ Neg,
+}
+
+#[derive(Clone, Debug)]
+pub enum GeneratorKind {
+ Async(AsyncGeneratorKind),
+ Gen,
+}
+
+#[derive(Clone, Debug)]
+pub enum AsyncGeneratorKind {
+ Block,
+ Closure,
+ Fn,
}
#[derive(Clone, Debug)]
pub enum Statement {
- Assign(Place, Operand),
+ Assign(Place, Rvalue),
Nop,
}
+// FIXME this is incomplete
+#[derive(Clone, Debug)]
+pub enum Rvalue {
+ Use(Operand),
+ CheckedBinaryOp(BinOp, Operand, Operand),
+ UnaryOp(UnOp, Operand),
+}
+
#[derive(Clone, Debug)]
pub enum Operand {
Copy(Place),
@@ -60,6 +132,7 @@ pub enum Operand {
#[derive(Clone, Debug)]
pub struct Place {
pub local: usize,
+ pub projection: String,
}
#[derive(Clone, Debug)]
diff --git a/compiler/rustc_smir/src/stable_mir/mod.rs b/compiler/rustc_smir/src/stable_mir/mod.rs
index 1d2efb5ea..612777b9c 100644
--- a/compiler/rustc_smir/src/stable_mir/mod.rs
+++ b/compiler/rustc_smir/src/stable_mir/mod.rs
@@ -11,7 +11,14 @@
//! There shouldn't be any direct references to internal compiler constructs in this module.
//! If you need an internal construct, consider using `rustc_internal` or `rustc_smir`.
+use std::cell::Cell;
+
+use crate::rustc_smir::Tables;
+
+use self::ty::{Ty, TyKind};
+
pub mod mir;
+pub mod ty;
/// Use String for now but we should replace it.
pub type Symbol = String;
@@ -41,7 +48,7 @@ pub struct CrateItem(pub(crate) DefId);
impl CrateItem {
pub fn body(&self) -> mir::Body {
- crate::rustc_smir::mir_body(self)
+ with(|cx| cx.mir_body(self))
}
}
@@ -49,25 +56,72 @@ impl CrateItem {
/// crate defines that. This is usually `main`, but could be
/// `start` if the crate is a no-std crate.
pub fn entry_fn() -> Option<CrateItem> {
- crate::rustc_smir::entry_fn()
+ with(|cx| cx.entry_fn())
}
/// Access to the local crate.
pub fn local_crate() -> Crate {
- crate::rustc_smir::local_crate()
+ with(|cx| cx.local_crate())
}
/// Try to find a crate with the given name.
pub fn find_crate(name: &str) -> Option<Crate> {
- crate::rustc_smir::find_crate(name)
+ with(|cx| cx.find_crate(name))
}
/// Try to find a crate with the given name.
pub fn external_crates() -> Vec<Crate> {
- crate::rustc_smir::external_crates()
+ with(|cx| cx.external_crates())
}
/// Retrieve all items in the local crate that have a MIR associated with them.
pub fn all_local_items() -> CrateItems {
- crate::rustc_smir::all_local_items()
+ with(|cx| cx.all_local_items())
+}
+
+pub trait Context {
+ fn entry_fn(&mut self) -> Option<CrateItem>;
+ /// Retrieve all items of the local crate that have a MIR associated with them.
+ fn all_local_items(&mut self) -> CrateItems;
+ fn mir_body(&mut self, item: &CrateItem) -> mir::Body;
+ /// Get information about the local crate.
+ fn local_crate(&self) -> Crate;
+ /// Retrieve a list of all external crates.
+ fn external_crates(&self) -> Vec<Crate>;
+
+ /// Find a crate with the given name.
+ fn find_crate(&self, name: &str) -> Option<Crate>;
+
+ /// Obtain the representation of a type.
+ fn ty_kind(&mut self, ty: Ty) -> TyKind;
+
+ /// HACK: Until we have fully stable consumers, we need an escape hatch
+ /// to get `DefId`s out of `CrateItem`s.
+ fn rustc_tables(&mut self, f: &mut dyn FnMut(&mut Tables<'_>));
+}
+
+thread_local! {
+ /// A thread local variable that stores a pointer to the tables mapping between TyCtxt
+ /// datastructures and stable MIR datastructures.
+ static TLV: Cell<*mut ()> = const { Cell::new(std::ptr::null_mut()) };
+}
+
+pub fn run(mut context: impl Context, f: impl FnOnce()) {
+ assert!(TLV.get().is_null());
+ fn g<'a>(mut context: &mut (dyn Context + 'a), f: impl FnOnce()) {
+ TLV.set(&mut context as *mut &mut _ as _);
+ f();
+ TLV.replace(std::ptr::null_mut());
+ }
+ g(&mut context, f);
+}
+
+/// Loads the current context and calls a function with it.
+/// Do not nest these, as that will ICE.
+pub(crate) fn with<R>(f: impl FnOnce(&mut dyn Context) -> R) -> R {
+ let ptr = TLV.replace(std::ptr::null_mut()) as *mut &mut dyn Context;
+ assert!(!ptr.is_null());
+ let ret = f(unsafe { *ptr });
+ TLV.set(ptr as _);
+ ret
}
diff --git a/compiler/rustc_smir/src/stable_mir/ty.rs b/compiler/rustc_smir/src/stable_mir/ty.rs
new file mode 100644
index 000000000..f27801b0f
--- /dev/null
+++ b/compiler/rustc_smir/src/stable_mir/ty.rs
@@ -0,0 +1,15 @@
+use super::with;
+
+#[derive(Copy, Clone, Debug)]
+pub struct Ty(pub usize);
+
+impl Ty {
+ pub fn kind(&self) -> TyKind {
+ with(|context| context.ty_kind(*self))
+ }
+}
+
+pub enum TyKind {
+ Bool,
+ Tuple(Vec<Ty>),
+}
diff --git a/compiler/rustc_span/src/def_id.rs b/compiler/rustc_span/src/def_id.rs
index b2c58caff..f65a6aa4f 100644
--- a/compiler/rustc_span/src/def_id.rs
+++ b/compiler/rustc_span/src/def_id.rs
@@ -1,12 +1,11 @@
use crate::{HashStableContext, Symbol};
use rustc_data_structures::fingerprint::Fingerprint;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher, ToStableHashKey};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher, ToStableHashKey};
use rustc_data_structures::unhash::Unhasher;
use rustc_data_structures::AtomicRef;
-use rustc_index::vec::Idx;
+use rustc_index::Idx;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
-use std::borrow::Borrow;
use std::fmt;
use std::hash::{BuildHasherDefault, Hash, Hasher};
@@ -105,20 +104,20 @@ impl DefPathHash {
/// originates from.
#[inline]
pub fn stable_crate_id(&self) -> StableCrateId {
- StableCrateId(self.0.as_value().0)
+ StableCrateId(self.0.split().0)
}
/// Returns the crate-local part of the [DefPathHash].
///
/// Used for tests.
#[inline]
- pub fn local_hash(&self) -> u64 {
- self.0.as_value().1
+ pub fn local_hash(&self) -> Hash64 {
+ self.0.split().1
}
/// Builds a new [DefPathHash] with the given [StableCrateId] and
/// `local_hash`, where `local_hash` must be unique within its crate.
- pub fn new(stable_crate_id: StableCrateId, local_hash: u64) -> DefPathHash {
+ pub fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> DefPathHash {
DefPathHash(Fingerprint::new(stable_crate_id.0, local_hash))
}
}
@@ -129,13 +128,6 @@ impl Default for DefPathHash {
}
}
-impl Borrow<Fingerprint> for DefPathHash {
- #[inline]
- fn borrow(&self) -> &Fingerprint {
- &self.0
- }
-}
-
/// A [`StableCrateId`] is a 64-bit hash of a crate name, together with all
/// `-Cmetadata` arguments, and some other data. It is to [`CrateNum`] what [`DefPathHash`] is to
/// [`DefId`]. It is stable across compilation sessions.
@@ -147,18 +139,19 @@ impl Borrow<Fingerprint> for DefPathHash {
///
/// For more information on the possibility of hash collisions in rustc,
/// see the discussion in [`DefId`].
-#[derive(Copy, Clone, Hash, PartialEq, Eq, PartialOrd, Ord, Debug)]
-#[derive(HashStable_Generic, Encodable, Decodable)]
-pub struct StableCrateId(pub(crate) u64);
+#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
+#[derive(Hash, HashStable_Generic, Encodable, Decodable)]
+pub struct StableCrateId(pub(crate) Hash64);
impl StableCrateId {
- pub fn to_u64(self) -> u64 {
- self.0
- }
-
/// Computes the stable ID for a crate with the given name and
/// `-Cmetadata` arguments.
- pub fn new(crate_name: Symbol, is_exe: bool, mut metadata: Vec<String>) -> StableCrateId {
+ pub fn new(
+ crate_name: Symbol,
+ is_exe: bool,
+ mut metadata: Vec<String>,
+ cfg_version: &'static str,
+ ) -> StableCrateId {
let mut hasher = StableHasher::new();
// We must hash the string text of the crate name, not the id, as the id is not stable
// across builds.
@@ -192,11 +185,22 @@ impl StableCrateId {
if let Some(val) = std::env::var_os("RUSTC_FORCE_RUSTC_VERSION") {
hasher.write(val.to_string_lossy().into_owned().as_bytes())
} else {
- hasher.write(option_env!("CFG_VERSION").unwrap_or("unknown version").as_bytes());
+ hasher.write(cfg_version.as_bytes())
}
StableCrateId(hasher.finish())
}
+
+ #[inline]
+ pub fn as_u64(self) -> u64 {
+ self.0.as_u64()
+ }
+}
+
+impl fmt::LowerHex for StableCrateId {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ fmt::LowerHex::fmt(&self.0, f)
+ }
}
rustc_index::newtype_index! {
diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs
index 08c441403..b219fde4d 100644
--- a/compiler/rustc_span/src/hygiene.rs
+++ b/compiler/rustc_span/src/hygiene.rs
@@ -33,10 +33,10 @@ use crate::def_id::{CrateNum, DefId, StableCrateId, CRATE_DEF_ID, LOCAL_CRATE};
use rustc_data_structures::fingerprint::Fingerprint;
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_data_structures::stable_hasher::HashingControls;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
use rustc_data_structures::unhash::UnhashMap;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_macros::HashStable_Generic;
use rustc_serialize::{Decodable, Decoder, Encodable, Encoder};
use std::fmt;
@@ -123,15 +123,15 @@ impl ExpnHash {
/// originates from.
#[inline]
pub fn stable_crate_id(self) -> StableCrateId {
- StableCrateId(self.0.as_value().0)
+ StableCrateId(self.0.split().0)
}
/// Returns the crate-local part of the [ExpnHash].
///
/// Used for tests.
#[inline]
- pub fn local_hash(self) -> u64 {
- self.0.as_value().1
+ pub fn local_hash(self) -> Hash64 {
+ self.0.split().1
}
#[inline]
@@ -141,7 +141,7 @@ impl ExpnHash {
/// Builds a new [ExpnHash] with the given [StableCrateId] and
/// `local_hash`, where `local_hash` must be unique within its crate.
- fn new(stable_crate_id: StableCrateId, local_hash: u64) -> ExpnHash {
+ fn new(stable_crate_id: StableCrateId, local_hash: Hash64) -> ExpnHash {
ExpnHash(Fingerprint::new(stable_crate_id.0, local_hash))
}
}
@@ -320,7 +320,6 @@ impl ExpnId {
// Stop going up the backtrace once include! is encountered
if expn_data.is_root()
|| expn_data.kind == ExpnKind::Macro(MacroKind::Bang, sym::include)
- || expn_data.kind == ExpnKind::Inlined
{
break;
}
@@ -350,7 +349,7 @@ pub struct HygieneData {
/// would have collisions without a disambiguator.
/// The keys of this map are always computed with `ExpnData.disambiguator`
/// set to 0.
- expn_data_disambiguators: FxHashMap<u64, u32>,
+ expn_data_disambiguators: FxHashMap<Hash64, u32>,
}
impl HygieneData {
@@ -1040,7 +1039,7 @@ impl ExpnData {
}
#[inline]
- fn hash_expn(&self, ctx: &mut impl HashStableContext) -> u64 {
+ fn hash_expn(&self, ctx: &mut impl HashStableContext) -> Hash64 {
let mut hasher = StableHasher::new();
self.hash_stable(ctx, &mut hasher);
hasher.finish()
@@ -1058,8 +1057,6 @@ pub enum ExpnKind {
AstPass(AstPass),
/// Desugaring done by the compiler during HIR lowering.
Desugaring(DesugaringKind),
- /// MIR inlining
- Inlined,
}
impl ExpnKind {
@@ -1073,7 +1070,6 @@ impl ExpnKind {
},
ExpnKind::AstPass(kind) => kind.descr().to_string(),
ExpnKind::Desugaring(kind) => format!("desugaring of {}", kind.descr()),
- ExpnKind::Inlined => "inlined source".to_string(),
}
}
}
@@ -1151,7 +1147,6 @@ pub enum DesugaringKind {
Await,
ForLoop,
WhileLoop,
- Replace,
}
impl DesugaringKind {
@@ -1167,7 +1162,6 @@ impl DesugaringKind {
DesugaringKind::OpaqueTy => "`impl Trait`",
DesugaringKind::ForLoop => "`for` loop",
DesugaringKind::WhileLoop => "`while` loop",
- DesugaringKind::Replace => "drop and replace",
}
}
}
diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs
index 28a8d8fc1..eae3f0fa0 100644
--- a/compiler/rustc_span/src/lib.rs
+++ b/compiler/rustc_span/src/lib.rs
@@ -60,7 +60,7 @@ pub mod fatal_error;
pub mod profiling;
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash128, Hash64, HashStable, StableHasher};
use rustc_data_structures::sync::{Lock, Lrc};
use std::borrow::Cow;
@@ -70,7 +70,6 @@ use std::hash::Hash;
use std::ops::{Add, Range, Sub};
use std::path::{Path, PathBuf};
use std::str::FromStr;
-use std::sync::Arc;
use md5::Digest;
use md5::Md5;
@@ -283,22 +282,22 @@ impl RealFileName {
pub enum FileName {
Real(RealFileName),
/// Call to `quote!`.
- QuoteExpansion(u64),
+ QuoteExpansion(Hash64),
/// Command line.
- Anon(u64),
+ Anon(Hash64),
/// Hack in `src/librustc_ast/parse.rs`.
// FIXME(jseyfried)
- MacroExpansion(u64),
- ProcMacroSourceCode(u64),
+ MacroExpansion(Hash64),
+ ProcMacroSourceCode(Hash64),
/// Strings provided as `--cfg [cfgspec]` stored in a `crate_cfg`.
- CfgSpec(u64),
+ CfgSpec(Hash64),
/// Strings provided as crate attributes in the CLI.
- CliCrateAttr(u64),
+ CliCrateAttr(Hash64),
/// Custom sources for explicit parser calls from plugins and drivers.
Custom(String),
DocTest(PathBuf, isize),
/// Post-substitution inline assembly from LLVM.
- InlineAsm(u64),
+ InlineAsm(Hash64),
}
impl From<PathBuf> for FileName {
@@ -595,12 +594,6 @@ impl Span {
matches!(outer_expn.kind, ExpnKind::Macro(..)) && outer_expn.collapse_debuginfo
}
- /// Returns `true` if this span comes from MIR inlining.
- pub fn is_inlined(self) -> bool {
- let outer_expn = self.ctxt().outer_expn_data();
- matches!(outer_expn.kind, ExpnKind::Inlined)
- }
-
/// Returns `true` if `span` originates in a derive-macro's expansion.
pub fn in_derive_expansion(self) -> bool {
matches!(self.ctxt().outer_expn_data().kind, ExpnKind::Macro(MacroKind::Derive, _))
@@ -755,7 +748,7 @@ impl Span {
self.ctxt()
.outer_expn_data()
.allow_internal_unstable
- .map_or(false, |features| features.iter().any(|&f| f == feature))
+ .is_some_and(|features| features.iter().any(|&f| f == feature))
}
/// Checks if this span arises from a compiler desugaring of kind `kind`.
@@ -1045,17 +1038,26 @@ impl fmt::Debug for Span {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
// Use the global `SourceMap` to print the span. If that's not
// available, fall back to printing the raw values.
- with_session_globals(|session_globals| {
- if let Some(source_map) = &*session_globals.source_map.borrow() {
- write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
- } else {
- f.debug_struct("Span")
- .field("lo", &self.lo())
- .field("hi", &self.hi())
- .field("ctxt", &self.ctxt())
- .finish()
- }
- })
+
+ fn fallback(span: Span, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ f.debug_struct("Span")
+ .field("lo", &span.lo())
+ .field("hi", &span.hi())
+ .field("ctxt", &span.ctxt())
+ .finish()
+ }
+
+ if SESSION_GLOBALS.is_set() {
+ with_session_globals(|session_globals| {
+ if let Some(source_map) = &*session_globals.source_map.borrow() {
+ write!(f, "{} ({:?})", source_map.span_to_diagnostic_string(*self), self.ctxt())
+ } else {
+ fallback(*self, f)
+ }
+ })
+ } else {
+ fallback(*self, f)
+ }
}
}
@@ -1249,29 +1251,6 @@ impl SourceFileHash {
}
}
-#[derive(HashStable_Generic)]
-#[derive(Copy, PartialEq, PartialOrd, Clone, Ord, Eq, Hash, Debug, Encodable, Decodable)]
-pub enum DebuggerVisualizerType {
- Natvis,
- GdbPrettyPrinter,
-}
-
-/// A single debugger visualizer file.
-#[derive(HashStable_Generic)]
-#[derive(Clone, Debug, Hash, PartialEq, Eq, PartialOrd, Ord, Encodable, Decodable)]
-pub struct DebuggerVisualizerFile {
- /// The complete debugger visualizer source.
- pub src: Arc<[u8]>,
- /// Indicates which visualizer type this targets.
- pub visualizer_type: DebuggerVisualizerType,
-}
-
-impl DebuggerVisualizerFile {
- pub fn new(src: Arc<[u8]>, visualizer_type: DebuggerVisualizerType) -> Self {
- DebuggerVisualizerFile { src, visualizer_type }
- }
-}
-
#[derive(Clone)]
pub enum SourceFileLines {
/// The source file lines, in decoded (random-access) form.
@@ -1344,7 +1323,7 @@ pub struct SourceFile {
/// Locations of characters removed during normalization.
pub normalized_pos: Vec<NormalizedPos>,
/// A hash of the filename, used for speeding up hashing in incremental compilation.
- pub name_hash: u128,
+ pub name_hash: Hash128,
/// Indicates which crate this `SourceFile` was imported from.
pub cnum: CrateNum,
}
@@ -1473,7 +1452,7 @@ impl<D: Decoder> Decodable<D> for SourceFile {
};
let multibyte_chars: Vec<MultiByteChar> = Decodable::decode(d);
let non_narrow_chars: Vec<NonNarrowChar> = Decodable::decode(d);
- let name_hash: u128 = Decodable::decode(d);
+ let name_hash = Decodable::decode(d);
let normalized_pos: Vec<NormalizedPos> = Decodable::decode(d);
let cnum: CrateNum = Decodable::decode(d);
SourceFile {
@@ -1515,7 +1494,7 @@ impl SourceFile {
let name_hash = {
let mut hasher: StableHasher = StableHasher::new();
name.hash(&mut hasher);
- hasher.finish::<u128>()
+ hasher.finish()
};
let end_pos = start_pos.to_usize() + src.len();
assert!(end_pos <= u32::MAX as usize);
@@ -1664,10 +1643,11 @@ impl SourceFile {
if let Some(ref src) = self.src {
Some(Cow::from(get_until_newline(src, begin)))
- } else if let Some(src) = self.external_src.borrow().get_source() {
- Some(Cow::Owned(String::from(get_until_newline(src, begin))))
} else {
- None
+ self.external_src
+ .borrow()
+ .get_source()
+ .map(|src| Cow::Owned(String::from(get_until_newline(src, begin))))
}
}
@@ -1736,6 +1716,28 @@ impl SourceFile {
BytePos::from_u32(pos.0 - self.start_pos.0 + diff)
}
+ /// Calculates a normalized byte position from a byte offset relative to the
+ /// start of the file.
+ ///
+ /// When we get an inline assembler error from LLVM during codegen, we
+ /// import the expanded assembly code as a new `SourceFile`, which can then
+ /// be used for error reporting with spans. However the byte offsets given
+ /// to us by LLVM are relative to the start of the original buffer, not the
+ /// normalized one. Hence we need to convert those offsets to the normalized
+ /// form when constructing spans.
+ pub fn normalized_byte_pos(&self, offset: u32) -> BytePos {
+ let diff = match self
+ .normalized_pos
+ .binary_search_by(|np| (np.pos.0 + np.diff).cmp(&(self.start_pos.0 + offset)))
+ {
+ Ok(i) => self.normalized_pos[i].diff,
+ Err(i) if i == 0 => 0,
+ Err(i) => self.normalized_pos[i - 1].diff,
+ };
+
+ BytePos::from_u32(self.start_pos.0 + offset - diff)
+ }
+
/// Converts an absolute `BytePos` to a `CharPos` relative to the `SourceFile`.
pub fn bytepos_to_file_charpos(&self, bpos: BytePos) -> CharPos {
// The number of extra bytes due to multibyte chars in the `SourceFile`.
@@ -2160,9 +2162,7 @@ where
};
Hash::hash(&TAG_VALID_SPAN, hasher);
- // We truncate the stable ID hash and line and column numbers. The chances
- // of causing a collision this way should be minimal.
- Hash::hash(&(file.name_hash as u64), hasher);
+ Hash::hash(&file.name_hash, hasher);
// Hash both the length and the end location (line/column) of a span. If we
// hash only the length, for example, then two otherwise equal spans with
@@ -2193,6 +2193,7 @@ pub struct ErrorGuaranteed(());
impl ErrorGuaranteed {
/// To be used only if you really know what you are doing... ideally, we would find a way to
/// eliminate all calls to this method.
+ #[deprecated = "`Session::delay_span_bug` should be preferred over this function"]
pub fn unchecked_claim_error_was_emitted() -> Self {
ErrorGuaranteed(())
}
diff --git a/compiler/rustc_span/src/source_map.rs b/compiler/rustc_span/src/source_map.rs
index 56573814e..1824510a9 100644
--- a/compiler/rustc_span/src/source_map.rs
+++ b/compiler/rustc_span/src/source_map.rs
@@ -13,8 +13,10 @@ pub use crate::hygiene::{ExpnData, ExpnKind};
pub use crate::*;
use rustc_data_structures::fx::FxHashMap;
-use rustc_data_structures::stable_hasher::StableHasher;
-use rustc_data_structures::sync::{AtomicU32, Lrc, MappedReadGuard, ReadGuard, RwLock};
+use rustc_data_structures::stable_hasher::{Hash128, Hash64, StableHasher};
+use rustc_data_structures::sync::{
+ AtomicU32, IntoDynSyncSend, Lrc, MappedReadGuard, ReadGuard, RwLock,
+};
use std::cmp;
use std::hash::Hash;
use std::path::{self, Path, PathBuf};
@@ -138,7 +140,7 @@ impl FileLoader for RealFileLoader {
pub struct StableSourceFileId {
/// A hash of the source file's [`FileName`]. This is hash so that it's size
/// is more predictable than if we included the actual [`FileName`] value.
- pub file_name_hash: u64,
+ pub file_name_hash: Hash64,
/// The [`CrateNum`] of the crate this source file was originally parsed for.
/// We cannot include this information in the hash because at the time
@@ -176,7 +178,7 @@ pub struct SourceMap {
used_address_space: AtomicU32,
files: RwLock<SourceMapFiles>,
- file_loader: Box<dyn FileLoader + Sync + Send>,
+ file_loader: IntoDynSyncSend<Box<dyn FileLoader + Sync + Send>>,
// This is used to apply the file path remapping as specified via
// `--remap-path-prefix` to all `SourceFile`s allocated within this `SourceMap`.
path_mapping: FilePathMapping,
@@ -202,7 +204,7 @@ impl SourceMap {
SourceMap {
used_address_space: AtomicU32::new(0),
files: Default::default(),
- file_loader,
+ file_loader: IntoDynSyncSend(file_loader),
path_mapping,
hash_kind,
}
@@ -331,7 +333,7 @@ impl SourceMap {
&self,
filename: FileName,
src_hash: SourceFileHash,
- name_hash: u128,
+ name_hash: Hash128,
source_len: usize,
cnum: CrateNum,
file_local_lines: Lock<SourceFileLines>,
@@ -483,7 +485,7 @@ impl SourceMap {
self.span_to_string(sp, FileNameDisplayPreference::Remapped)
}
- /// Format the span location suitable for pretty printing anotations with relative line numbers
+ /// Format the span location suitable for pretty printing annotations with relative line numbers
pub fn span_to_relative_line_string(&self, sp: Span, relative_to: Span) -> String {
if self.files.borrow().source_files.is_empty() || sp.is_dummy() || relative_to.is_dummy() {
return "no-location".to_string();
@@ -637,7 +639,7 @@ impl SourceMap {
self.span_to_source(sp, |src, start_index, end_index| {
Ok(src.get(start_index..end_index).is_some())
})
- .map_or(false, |is_accessible| is_accessible)
+ .is_ok_and(|is_accessible| is_accessible)
}
/// Returns the source snippet as `String` corresponding to the given `Span`.
@@ -777,7 +779,7 @@ impl SourceMap {
/// Given a 'Span', tries to tell if it's wrapped by "<>" or "()"
/// the algorithm searches if the next character is '>' or ')' after skipping white space
- /// then searches the previous charactoer to match '<' or '(' after skipping white space
+ /// then searches the previous character to match '<' or '(' after skipping white space
/// return true if wrapped by '<>' or '()'
pub fn span_wrapped_by_angle_or_parentheses(&self, span: Span) -> bool {
self.span_to_source(span, |src, start_index, end_index| {
@@ -833,7 +835,7 @@ impl SourceMap {
}
return Ok(true);
})
- .map_or(false, |is_accessible| is_accessible)
+ .is_ok_and(|is_accessible| is_accessible)
}
/// Given a `Span`, tries to get a shorter span ending just after the first occurrence of `char`
@@ -906,10 +908,8 @@ impl SourceMap {
let snippet = if let Some(ref src) = local_begin.sf.src {
Some(&src[start_index..])
- } else if let Some(src) = src.get_source() {
- Some(&src[start_index..])
} else {
- None
+ src.get_source().map(|src| &src[start_index..])
};
match snippet {
@@ -967,7 +967,7 @@ impl SourceMap {
for _ in 0..limit.unwrap_or(100_usize) {
sp = self.next_point(sp);
if let Ok(ref snippet) = self.span_to_snippet(sp) {
- if expect.map_or(false, |es| snippet == es) {
+ if expect.is_some_and(|es| snippet == es) {
break;
}
if expect.is_none() && snippet.chars().any(|c| !c.is_whitespace()) {
diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs
index c600298c5..1eea0f63c 100644
--- a/compiler/rustc_span/src/span_encoding.rs
+++ b/compiler/rustc_span/src/span_encoding.rs
@@ -181,19 +181,23 @@ impl Span {
#[inline]
pub fn ctxt(self) -> SyntaxContext {
let ctxt_or_tag = self.ctxt_or_tag as u32;
- if ctxt_or_tag <= MAX_CTXT {
- if self.len_or_tag == LEN_TAG || self.len_or_tag & PARENT_MASK == 0 {
- // Inline format or interned format with inline ctxt.
- SyntaxContext::from_u32(ctxt_or_tag)
+ // Check for interned format.
+ if self.len_or_tag == LEN_TAG {
+ if ctxt_or_tag == CTXT_TAG {
+ // Fully interned format.
+ let index = self.base_or_index;
+ with_span_interner(|interner| interner.spans[index as usize].ctxt)
} else {
- // Inline format or interned format with inline parent.
- // We know that the SyntaxContext is root.
- SyntaxContext::root()
+ // Interned format with inline ctxt.
+ SyntaxContext::from_u32(ctxt_or_tag)
}
+ } else if self.len_or_tag & PARENT_MASK == 0 {
+ // Inline format with inline ctxt.
+ SyntaxContext::from_u32(ctxt_or_tag)
} else {
- // Interned format.
- let index = self.base_or_index;
- with_span_interner(|interner| interner.spans[index as usize].ctxt)
+ // Inline format with inline parent.
+ // We know that the SyntaxContext is root.
+ SyntaxContext::root()
}
}
}
diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs
index 6bfae3771..874d578fe 100644
--- a/compiler/rustc_span/src/symbol.rs
+++ b/compiler/rustc_span/src/symbol.rs
@@ -95,6 +95,7 @@ symbols! {
// Weak keywords, have special meaning only in specific contexts.
Auto: "auto",
+ Builtin: "builtin",
Catch: "catch",
Default: "default",
MacroRules: "macro_rules",
@@ -129,8 +130,7 @@ symbols! {
Any,
Arc,
Argument,
- ArgumentV1,
- ArgumentV1Methods,
+ ArgumentMethods,
Arguments,
AsMut,
AsRef,
@@ -164,6 +164,7 @@ symbols! {
Capture,
Center,
Clone,
+ ConstParamTy,
Context,
Continue,
Copy,
@@ -204,9 +205,11 @@ symbols! {
HashSet,
Hasher,
Implied,
+ IndexOutput,
Input,
Into,
IntoDiagnostic,
+ IntoFuture,
IntoIterator,
IoRead,
IoWrite,
@@ -439,9 +442,12 @@ symbols! {
breakpoint,
bridge,
bswap,
+ builtin_syntax,
c_str,
+ c_str_literals,
c_unwind,
c_variadic,
+ c_void,
call,
call_mut,
call_once,
@@ -458,6 +464,7 @@ symbols! {
cfg_doctest,
cfg_eval,
cfg_hide,
+ cfg_overflow_checks,
cfg_panic,
cfg_sanitize,
cfg_target_abi,
@@ -469,6 +476,7 @@ symbols! {
cfg_target_vendor,
cfg_version,
cfi,
+ cfi_encoding,
char,
client,
clippy,
@@ -530,6 +538,7 @@ symbols! {
const_mut_refs,
const_panic,
const_panic_fmt,
+ const_param_ty,
const_precise_live_drops,
const_raw_ptr_deref,
const_raw_ptr_to_usize_cast,
@@ -650,6 +659,7 @@ symbols! {
edition_panic,
eh_catch_typeinfo,
eh_personality,
+ emit,
emit_enum,
emit_enum_variant,
emit_enum_variant_arg,
@@ -981,6 +991,7 @@ symbols! {
needs_panic_runtime,
neg,
negate_unsigned,
+ negative_bounds,
negative_impls,
neon,
never,
@@ -1024,6 +1035,7 @@ symbols! {
non_exhaustive_omitted_patterns_lint,
non_lifetime_binders,
non_modrs_mods,
+ none,
nontemporal_store,
noop_method_borrow,
noop_method_clone,
@@ -1036,6 +1048,7 @@ symbols! {
object_safe_for_dispatch,
of,
offset,
+ offset_of,
omit_gdb_pretty_printer_section,
on,
on_unimplemented,
@@ -1054,6 +1067,7 @@ symbols! {
or_patterns,
other,
out,
+ overflow_checks,
overlapping_marker_traits,
owned_box,
packed,
@@ -1199,6 +1213,7 @@ symbols! {
require,
residual,
result,
+ resume,
return_position_impl_trait_in_trait,
return_type_notation,
rhs,
@@ -1318,6 +1333,8 @@ symbols! {
s,
safety,
sanitize,
+ sanitizer_cfi_generalize_pointers,
+ sanitizer_cfi_normalize_integers,
sanitizer_runtime,
saturating_add,
saturating_sub,
@@ -1503,6 +1520,7 @@ symbols! {
transmute_generic_consts,
transmute_opts,
transmute_trait,
+ transmute_unchecked,
transparent,
transparent_enums,
transparent_unions,
@@ -1566,6 +1584,7 @@ symbols! {
unrestricted_attribute_tokens,
unsafe_block_in_unsafe_fn,
unsafe_cell,
+ unsafe_cell_from_mut,
unsafe_no_drop_flag,
unsafe_pin_internals,
unsize,
@@ -1632,6 +1651,7 @@ symbols! {
write_bytes,
write_macro,
write_str,
+ write_via_move,
writeln_macro,
x87_reg,
xer,
@@ -1986,8 +2006,9 @@ impl Interner {
name
}
- // Get the symbol as a string. `Symbol::as_str()` should be used in
- // preference to this function.
+ /// Get the symbol as a string.
+ ///
+ /// [`Symbol::as_str()`] should be used in preference to this function.
fn get(&self, symbol: Symbol) -> &str {
self.0.lock().strings[symbol.0.as_usize()]
}
diff --git a/compiler/rustc_span/src/tests.rs b/compiler/rustc_span/src/tests.rs
index 5b3915c33..a242ad6d1 100644
--- a/compiler/rustc_span/src/tests.rs
+++ b/compiler/rustc_span/src/tests.rs
@@ -3,8 +3,12 @@ use super::*;
#[test]
fn test_lookup_line() {
let source = "abcdefghijklm\nabcdefghij\n...".to_owned();
- let sf =
- SourceFile::new(FileName::Anon(0), source, BytePos(3), SourceFileHashAlgorithm::Sha256);
+ let sf = SourceFile::new(
+ FileName::Anon(Hash64::ZERO),
+ source,
+ BytePos(3),
+ SourceFileHashAlgorithm::Sha256,
+ );
sf.lines(|lines| assert_eq!(lines, &[BytePos(3), BytePos(17), BytePos(28)]));
assert_eq!(sf.lookup_line(BytePos(0)), None);
diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml
index 4e447eab0..052ef8bb9 100644
--- a/compiler/rustc_symbol_mangling/Cargo.toml
+++ b/compiler/rustc_symbol_mangling/Cargo.toml
@@ -15,6 +15,7 @@ twox-hash = "1.6.3"
rustc_span = { path = "../rustc_span" }
rustc_middle = { path = "../rustc_middle" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_target = { path = "../rustc_target" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_session = { path = "../rustc_session" }
diff --git a/compiler/rustc_symbol_mangling/src/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs
index 5cbca8192..254ede4e6 100644
--- a/compiler/rustc_symbol_mangling/src/legacy.rs
+++ b/compiler/rustc_symbol_mangling/src/legacy.rs
@@ -1,4 +1,4 @@
-use rustc_data_structures::stable_hasher::{HashStable, StableHasher};
+use rustc_data_structures::stable_hasher::{Hash64, HashStable, StableHasher};
use rustc_hir::def_id::CrateNum;
use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData};
use rustc_middle::ty::print::{PrettyPrinter, Print, Printer};
@@ -93,7 +93,7 @@ fn get_symbol_hash<'tcx>(
item_type: Ty<'tcx>,
instantiating_crate: Option<CrateNum>,
-) -> u64 {
+) -> Hash64 {
let def_id = instance.def_id();
let substs = instance.substs;
debug!("get_symbol_hash(def_id={:?}, parameters={:?})", def_id, substs);
@@ -108,7 +108,7 @@ fn get_symbol_hash<'tcx>(
tcx.def_path_hash(def_id).hash_stable(&mut hcx, &mut hasher);
// Include the main item-type. Note that, in this case, the
- // assertions about `needs_subst` may not hold, but this item-type
+ // assertions about `has_param` may not hold, but this item-type
// ought to be the same for every reference anyway.
assert!(!item_type.has_erasable_regions());
hcx.while_hashing_spans(false, |hcx| {
@@ -138,7 +138,7 @@ fn get_symbol_hash<'tcx>(
});
// 64 bits should be enough to avoid collisions.
- hasher.finish::<u64>()
+ hasher.finish::<Hash64>()
})
}
@@ -176,7 +176,7 @@ impl SymbolPath {
}
}
- fn finish(mut self, hash: u64) -> String {
+ fn finish(mut self, hash: Hash64) -> String {
self.finalize_pending_component();
// E = end name-sequence
let _ = write!(self.result, "17h{hash:016x}E");
@@ -220,7 +220,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
match *ty.kind() {
// Print all nominal types as paths (unlike `pretty_print_type`).
ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => self.print_def_path(def_id, substs),
@@ -241,6 +241,8 @@ impl<'tcx> Printer<'tcx> for &mut SymbolPrinter<'tcx> {
Ok(self)
}
+ ty::Alias(ty::Inherent, _) => panic!("unexpected inherent projection"),
+
_ => self.pretty_print_type(ty),
}
}
diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs
index c2fd3304f..692542da7 100644
--- a/compiler/rustc_symbol_mangling/src/lib.rs
+++ b/compiler/rustc_symbol_mangling/src/lib.rs
@@ -101,13 +101,13 @@ extern crate rustc_middle;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
+use rustc_fluent_macro::fluent_messages;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::{CrateNum, LOCAL_CRATE};
-use rustc_macros::fluent_messages;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags;
use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrs;
use rustc_middle::mir::mono::{InstantiationMode, MonoItem};
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt};
use rustc_session::config::SymbolManglingVersion;
diff --git a/compiler/rustc_symbol_mangling/src/test.rs b/compiler/rustc_symbol_mangling/src/test.rs
index b4d5b7f36..985b22107 100644
--- a/compiler/rustc_symbol_mangling/src/test.rs
+++ b/compiler/rustc_symbol_mangling/src/test.rs
@@ -83,7 +83,7 @@ impl SymbolNamesTest<'_> {
tcx.sess.emit_err(TestOutput {
span: attr.span,
kind: Kind::DefPath,
- content: with_no_trimmed_paths!(tcx.def_path_str(def_id.to_def_id())),
+ content: with_no_trimmed_paths!(tcx.def_path_str(def_id)),
});
}
}
diff --git a/compiler/rustc_symbol_mangling/src/typeid.rs b/compiler/rustc_symbol_mangling/src/typeid.rs
index 53983bed7..cda16e3a3 100644
--- a/compiler/rustc_symbol_mangling/src/typeid.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid.rs
@@ -1,42 +1,87 @@
-// For more information about type metadata and type metadata identifiers for cross-language LLVM
-// CFI support, see Type metadata in the design document in the tracking issue #89653.
-
-use rustc_middle::ty::{FnSig, Ty, TyCtxt};
+/// Type metadata identifiers for LLVM Control Flow Integrity (CFI) and cross-language LLVM CFI
+/// support.
+///
+/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+/// see design document in the tracking issue #89653.
+use bitflags::bitflags;
+use rustc_middle::ty::{FnSig, Instance, Ty, TyCtxt};
use rustc_target::abi::call::FnAbi;
use std::hash::Hasher;
use twox_hash::XxHash64;
+bitflags! {
+ /// Options for typeid_for_fnabi and typeid_for_fnsig.
+ pub struct TypeIdOptions: u32 {
+ const GENERALIZE_POINTERS = 1;
+ const GENERALIZE_REPR_C = 2;
+ const NORMALIZE_INTEGERS = 4;
+ }
+}
+
mod typeid_itanium_cxx_abi;
-use typeid_itanium_cxx_abi::TypeIdOptions;
/// Returns a type metadata identifier for the specified FnAbi.
-pub fn typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> String {
- typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS)
+pub fn typeid_for_fnabi<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options)
}
/// Returns a type metadata identifier for the specified FnSig.
-pub fn typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> String {
- typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS)
+pub fn typeid_for_fnsig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_sig: &FnSig<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options)
+}
+
+/// Returns a type metadata identifier for the specified Instance.
+pub fn typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options)
+}
+
+/// Returns a KCFI type metadata identifier for the specified FnAbi.
+pub fn kcfi_typeid_for_fnabi<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_abi: &FnAbi<'tcx, Ty<'tcx>>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+ let mut hash: XxHash64 = Default::default();
+ hash.write(typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, options).as_bytes());
+ hash.finish() as u32
}
-/// Returns an LLVM KCFI type metadata identifier for the specified FnAbi.
-pub fn kcfi_typeid_for_fnabi<'tcx>(tcx: TyCtxt<'tcx>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> u32 {
- // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
- // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+/// Returns a KCFI type metadata identifier for the specified FnSig.
+pub fn kcfi_typeid_for_fnsig<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ fn_sig: &FnSig<'tcx>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
- hash.write(
- typeid_itanium_cxx_abi::typeid_for_fnabi(tcx, fn_abi, TypeIdOptions::NO_OPTIONS).as_bytes(),
- );
+ hash.write(typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, options).as_bytes());
hash.finish() as u32
}
-/// Returns an LLVM KCFI type metadata identifier for the specified FnSig.
-pub fn kcfi_typeid_for_fnsig<'tcx>(tcx: TyCtxt<'tcx>, fn_sig: &FnSig<'tcx>) -> u32 {
- // An LLVM KCFI type metadata identifier is a 32-bit constant produced by taking the lower half
- // of the xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
+/// Returns a KCFI type metadata identifier for the specified Instance.
+pub fn kcfi_typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> u32 {
+ // A KCFI type metadata identifier is a 32-bit constant produced by taking the lower half of the
+ // xxHash64 of the type metadata identifier. (See llvm/llvm-project@cff5bef.)
let mut hash: XxHash64 = Default::default();
- hash.write(
- typeid_itanium_cxx_abi::typeid_for_fnsig(tcx, fn_sig, TypeIdOptions::NO_OPTIONS).as_bytes(),
- );
+ hash.write(typeid_itanium_cxx_abi::typeid_for_instance(tcx, instance, options).as_bytes());
hash.finish() as u32
}
diff --git a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
index 1a679f32c..9fa49123a 100644
--- a/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
+++ b/compiler/rustc_symbol_mangling/src/typeid/typeid_itanium_cxx_abi.rs
@@ -1,26 +1,30 @@
-// For more information about type metadata and type metadata identifiers for cross-language LLVM
-// CFI support, see Type metadata in the design document in the tracking issue #89653.
-
-// FIXME(rcvalle): Identify C char and integer type uses and encode them with their respective
-// builtin type encodings as specified by the Itanium C++ ABI for extern function types with the "C"
-// calling convention to use this encoding for cross-language LLVM CFI.
-
-use bitflags::bitflags;
+/// Type metadata identifiers (using Itanium C++ ABI mangling for encoding) for LLVM Control Flow
+/// Integrity (CFI) and cross-language LLVM CFI support.
+///
+/// Encodes type metadata identifiers for LLVM CFI and cross-language LLVM CFI support using Itanium
+/// C++ ABI mangling for encoding with vendor extended type qualifiers and types for Rust types that
+/// are not used across the FFI boundary.
+///
+/// For more information about LLVM CFI and cross-language LLVM CFI support for the Rust compiler,
+/// see design document in the tracking issue #89653.
use core::fmt::Display;
use rustc_data_structures::base_n;
use rustc_data_structures::fx::FxHashMap;
+use rustc_errors::DiagnosticMessage;
use rustc_hir as hir;
use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef};
use rustc_middle::ty::{
- self, Const, ExistentialPredicate, FloatTy, FnSig, IntTy, List, Region, RegionKind, TermKind,
- Ty, TyCtxt, UintTy,
+ self, Const, ExistentialPredicate, FloatTy, FnSig, Instance, IntTy, List, Region, RegionKind,
+ TermKind, Ty, TyCtxt, UintTy,
};
use rustc_span::def_id::DefId;
-use rustc_span::symbol::sym;
+use rustc_span::sym;
use rustc_target::abi::call::{Conv, FnAbi};
use rustc_target::spec::abi::Abi;
use std::fmt::Write as _;
+use crate::typeid::TypeIdOptions;
+
/// Type and extended type qualifiers.
#[derive(Eq, Hash, PartialEq)]
enum TyQ {
@@ -38,15 +42,6 @@ enum DictKey<'tcx> {
Predicate(ExistentialPredicate<'tcx>),
}
-bitflags! {
- /// Options for typeid_for_fnabi and typeid_for_fnsig.
- pub struct TypeIdOptions: u32 {
- const NO_OPTIONS = 0;
- const GENERALIZE_POINTERS = 1;
- const GENERALIZE_REPR_C = 2;
- }
-}
-
/// Options for encode_ty.
type EncodeTyOptions = TypeIdOptions;
@@ -91,21 +86,6 @@ fn compress<'tcx>(
}
}
-// FIXME(rcvalle): Move to compiler/rustc_middle/src/ty/sty.rs after C types work is done, possibly
-// along with other is_c_type methods.
-/// Returns whether a `ty::Ty` is `c_void`.
-fn is_c_void_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
- match ty.kind() {
- ty::Adt(adt_def, ..) => {
- let def_id = adt_def.0.did;
- let crate_name = tcx.crate_name(def_id.krate);
- tcx.item_name(def_id).as_str() == "c_void"
- && (crate_name == sym::core || crate_name == sym::std || crate_name == sym::libc)
- }
- _ => false,
- }
-}
-
/// Encodes a const using the Itanium C++ ABI as a literal argument (see
/// <https://itanium-cxx-abi.github.io/cxx-abi/abi.html#mangling.literal>).
fn encode_const<'tcx>(
@@ -292,12 +272,11 @@ fn encode_region<'tcx>(
s.push('E');
compress(dict, DictKey::Region(region), &mut s);
}
- RegionKind::ReErased => {
+ RegionKind::ReEarlyBound(..) | RegionKind::ReErased => {
s.push_str("u6region");
compress(dict, DictKey::Region(region), &mut s);
}
- RegionKind::ReEarlyBound(..)
- | RegionKind::ReFree(..)
+ RegionKind::ReFree(..)
| RegionKind::ReStatic
| RegionKind::ReError(_)
| RegionKind::ReVar(..)
@@ -406,7 +385,7 @@ fn encode_ty_name(tcx: TyCtxt<'_>, def_id: DefId) -> String {
// Crate disambiguator and name
s.push('C');
- s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).to_u64()));
+ s.push_str(&to_disambiguator(tcx.stable_crate_id(def_path.krate).as_u64()));
let crate_name = tcx.crate_name(def_path.krate).to_string();
let _ = write!(s, "{}{}", crate_name.len(), &crate_name);
@@ -448,6 +427,12 @@ fn encode_ty<'tcx>(
match ty.kind() {
// Primitive types
+
+ // Rust's bool has the same layout as C17's _Bool, that is, its size and alignment are
+ // implementation-defined. Any bool can be cast into an integer, taking on the values 1
+ // (true) or 0 (false).
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
ty::Bool => {
typeid.push('b');
}
@@ -535,9 +520,33 @@ fn encode_ty<'tcx>(
// User-defined types
ty::Adt(adt_def, substs) => {
let mut s = String::new();
- let def_id = adt_def.0.did;
- if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
- // For cross-language CFI support, the encoding must be compatible at the FFI
+ let def_id = adt_def.did();
+ if let Some(cfi_encoding) = tcx.get_attr(def_id, sym::cfi_encoding) {
+ // Use user-defined CFI encoding for type
+ if let Some(value_str) = cfi_encoding.value_str() {
+ if !value_str.to_string().trim().is_empty() {
+ s.push_str(&value_str.to_string().trim());
+ } else {
+ #[allow(
+ rustc::diagnostic_outside_of_impl,
+ rustc::untranslatable_diagnostic
+ )]
+ tcx.sess
+ .struct_span_err(
+ cfi_encoding.span,
+ DiagnosticMessage::Str(format!(
+ "invalid `cfi_encoding` for `{:?}`",
+ ty.kind()
+ )),
+ )
+ .emit();
+ }
+ } else {
+ bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
+ }
+ compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+ } else if options.contains(EncodeTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c() {
+ // For cross-language LLVM CFI support, the encoding must be compatible at the FFI
// boundary. For instance:
//
// struct type1 {};
@@ -567,8 +576,33 @@ fn encode_ty<'tcx>(
ty::Foreign(def_id) => {
// <length><name>, where <name> is <unscoped-name>
let mut s = String::new();
- let name = tcx.item_name(*def_id).to_string();
- let _ = write!(s, "{}{}", name.len(), &name);
+ if let Some(cfi_encoding) = tcx.get_attr(*def_id, sym::cfi_encoding) {
+ // Use user-defined CFI encoding for type
+ if let Some(value_str) = cfi_encoding.value_str() {
+ if !value_str.to_string().trim().is_empty() {
+ s.push_str(&value_str.to_string().trim());
+ } else {
+ #[allow(
+ rustc::diagnostic_outside_of_impl,
+ rustc::untranslatable_diagnostic
+ )]
+ tcx.sess
+ .struct_span_err(
+ cfi_encoding.span,
+ DiagnosticMessage::Str(format!(
+ "invalid `cfi_encoding` for `{:?}`",
+ ty.kind()
+ )),
+ )
+ .emit();
+ }
+ } else {
+ bug!("encode_ty: invalid `cfi_encoding` for `{:?}`", ty.kind());
+ }
+ } else {
+ let name = tcx.item_name(*def_id).to_string();
+ let _ = write!(s, "{}{}", name.len(), &name);
+ }
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
@@ -618,7 +652,7 @@ fn encode_ty<'tcx>(
ty::FnPtr(fn_sig) => {
// PF<return-type><parameter-type1..parameter-typeN>E
let mut s = String::from("P");
- s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::NO_OPTIONS));
+ s.push_str(&encode_fnsig(tcx, &fn_sig.skip_binder(), dict, TypeIdOptions::empty()));
compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
typeid.push_str(&s);
}
@@ -638,6 +672,14 @@ fn encode_ty<'tcx>(
typeid.push_str(&s);
}
+ // Type parameters
+ ty::Param(..) => {
+ // u5param as vendor extended type
+ let mut s = String::from("u5param");
+ compress(dict, DictKey::Ty(ty, TyQ::None), &mut s);
+ typeid.push_str(&s);
+ }
+
// Unexpected types
ty::Bound(..)
| ty::Error(..)
@@ -645,7 +687,6 @@ fn encode_ty<'tcx>(
| ty::GeneratorWitnessMIR(..)
| ty::Infer(..)
| ty::Alias(..)
- | ty::Param(..)
| ty::Placeholder(..) => {
bug!("encode_ty: unexpected `{:?}`", ty.kind());
}
@@ -654,23 +695,96 @@ fn encode_ty<'tcx>(
typeid
}
+/// Transforms predicates for being encoded and used in the substitution dictionary.
+fn transform_predicates<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ predicates: &List<ty::PolyExistentialPredicate<'tcx>>,
+ _options: EncodeTyOptions,
+) -> &'tcx List<ty::PolyExistentialPredicate<'tcx>> {
+ let predicates: Vec<ty::PolyExistentialPredicate<'tcx>> = predicates
+ .iter()
+ .filter_map(|predicate| match predicate.skip_binder() {
+ ty::ExistentialPredicate::Trait(trait_ref) => {
+ let trait_ref = ty::TraitRef::identity(tcx, trait_ref.def_id);
+ Some(ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
+ )))
+ }
+ ty::ExistentialPredicate::Projection(..) => None,
+ ty::ExistentialPredicate::AutoTrait(..) => Some(predicate),
+ })
+ .collect();
+ tcx.mk_poly_existential_predicates(&predicates)
+}
+
+/// Transforms substs for being encoded and used in the substitution dictionary.
+fn transform_substs<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ substs: SubstsRef<'tcx>,
+ options: TransformTyOptions,
+) -> SubstsRef<'tcx> {
+ let substs = substs.iter().map(|subst| match subst.unpack() {
+ GenericArgKind::Type(ty) if ty.is_c_void(tcx) => tcx.mk_unit().into(),
+ GenericArgKind::Type(ty) => transform_ty(tcx, ty, options).into(),
+ _ => subst,
+ });
+ tcx.mk_substs_from_iter(substs)
+}
+
// Transforms a ty:Ty for being encoded and used in the substitution dictionary. It transforms all
-// c_void types into unit types unconditionally, and generalizes all pointers if
-// TransformTyOptions::GENERALIZE_POINTERS option is set.
-#[instrument(level = "trace", skip(tcx))]
+// c_void types into unit types unconditionally, generalizes pointers if
+// TransformTyOptions::GENERALIZE_POINTERS option is set, and normalizes integers if
+// TransformTyOptions::NORMALIZE_INTEGERS option is set.
fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptions) -> Ty<'tcx> {
let mut ty = ty;
match ty.kind() {
- ty::Bool
- | ty::Int(..)
- | ty::Uint(..)
- | ty::Float(..)
- | ty::Char
- | ty::Str
- | ty::Never
- | ty::Foreign(..)
- | ty::Dynamic(..) => {}
+ ty::Float(..) | ty::Char | ty::Str | ty::Never | ty::Foreign(..) => {}
+
+ ty::Bool => {
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ // Note: on all platforms that Rust's currently supports, its size and alignment are
+ // 1, and its ABI class is INTEGER - see Rust Layout and ABIs.
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#bool.)
+ //
+ // Clang represents bool as an 8-bit unsigned integer.
+ ty = tcx.types.u8;
+ }
+ }
+
+ ty::Int(..) | ty::Uint(..) => {
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ // Note: C99 7.18.2.4 requires uintptr_t and intptr_t to be at least 16-bit wide.
+ // All platforms we currently support have a C platform, and as a consequence,
+ // isize/usize are at least 16-bit wide for all of them.
+ //
+ // (See https://rust-lang.github.io/unsafe-code-guidelines/layout/scalars.html#isize-and-usize.)
+ match ty.kind() {
+ ty::Int(IntTy::Isize) => match tcx.sess.target.pointer_width {
+ 16 => ty = tcx.types.i16,
+ 32 => ty = tcx.types.i32,
+ 64 => ty = tcx.types.i64,
+ 128 => ty = tcx.types.i128,
+ _ => bug!(
+ "transform_ty: unexpected pointer width `{}`",
+ tcx.sess.target.pointer_width
+ ),
+ },
+ ty::Uint(UintTy::Usize) => match tcx.sess.target.pointer_width {
+ 16 => ty = tcx.types.u16,
+ 32 => ty = tcx.types.u32,
+ 64 => ty = tcx.types.u64,
+ 128 => ty = tcx.types.u128,
+ _ => bug!(
+ "transform_ty: unexpected pointer width `{}`",
+ tcx.sess.target.pointer_width
+ ),
+ },
+ _ => (),
+ }
+ }
+ }
_ if ty.is_unit() => {}
@@ -688,18 +802,23 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
}
ty::Adt(adt_def, substs) => {
- if is_c_void_ty(tcx, ty) {
+ if ty.is_c_void(tcx) {
ty = tcx.mk_unit();
} else if options.contains(TransformTyOptions::GENERALIZE_REPR_C) && adt_def.repr().c()
{
ty = tcx.mk_adt(*adt_def, ty::List::empty());
} else if adt_def.repr().transparent() && adt_def.is_struct() {
+ // Don't transform repr(transparent) types with an user-defined CFI encoding to
+ // preserve the user-defined CFI encoding.
+ if let Some(_) = tcx.get_attr(adt_def.did(), sym::cfi_encoding) {
+ return ty;
+ }
let variant = adt_def.non_enum_variant();
let param_env = tcx.param_env(variant.def_id);
let field = variant.fields.iter().find(|field| {
let ty = tcx.type_of(field.did).subst_identity();
let is_zst =
- tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.is_zst());
+ tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.is_zst());
!is_zst
});
if let Some(field) = field {
@@ -793,6 +912,14 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
}
}
+ ty::Dynamic(predicates, _region, kind) => {
+ ty = tcx.mk_dynamic(
+ transform_predicates(tcx, predicates, options),
+ tcx.lifetimes.re_erased,
+ *kind,
+ );
+ }
+
ty::Bound(..)
| ty::Error(..)
| ty::GeneratorWitness(..)
@@ -808,26 +935,6 @@ fn transform_ty<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, options: TransformTyOptio
ty
}
-/// Transforms substs for being encoded and used in the substitution dictionary.
-fn transform_substs<'tcx>(
- tcx: TyCtxt<'tcx>,
- substs: SubstsRef<'tcx>,
- options: TransformTyOptions,
-) -> SubstsRef<'tcx> {
- let substs = substs.iter().map(|subst| {
- if let GenericArgKind::Type(ty) = subst.unpack() {
- if is_c_void_ty(tcx, ty) {
- tcx.mk_unit().into()
- } else {
- transform_ty(tcx, ty, options).into()
- }
- } else {
- subst
- }
- });
- tcx.mk_substs_from_iter(substs)
-}
-
/// Returns a type metadata identifier for the specified FnAbi using the Itanium C++ ABI with vendor
/// extended type qualifiers and types for Rust types that are not used at the FFI boundary.
#[instrument(level = "trace", skip(tcx))]
@@ -893,6 +1000,15 @@ pub fn typeid_for_fnabi<'tcx>(
// Close the "F..E" pair
typeid.push('E');
+ // Add encoding suffixes
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ typeid.push_str(".normalized");
+ }
+
+ if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
+ typeid.push_str(".generalized");
+ }
+
typeid
}
@@ -919,5 +1035,67 @@ pub fn typeid_for_fnsig<'tcx>(
// Encode the function signature
typeid.push_str(&encode_fnsig(tcx, fn_sig, &mut dict, options));
+ // Add encoding suffixes
+ if options.contains(EncodeTyOptions::NORMALIZE_INTEGERS) {
+ typeid.push_str(".normalized");
+ }
+
+ if options.contains(EncodeTyOptions::GENERALIZE_POINTERS) {
+ typeid.push_str(".generalized");
+ }
+
typeid
}
+
+/// Returns a type metadata identifier for the specified Instance using the Itanium C++ ABI with
+/// vendor extended type qualifiers and types for Rust types that are not used at the FFI boundary.
+pub fn typeid_for_instance<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ instance: &Instance<'tcx>,
+ options: TypeIdOptions,
+) -> String {
+ let fn_abi = tcx
+ .fn_abi_of_instance(tcx.param_env(instance.def_id()).and((*instance, ty::List::empty())))
+ .unwrap_or_else(|instance| {
+ bug!("typeid_for_instance: couldn't get fn_abi of instance {:?}", instance)
+ });
+
+ // If this instance is a method and self is a reference, get the impl it belongs to
+ let impl_def_id = tcx.impl_of_method(instance.def_id());
+ if impl_def_id.is_some() && !fn_abi.args.is_empty() && fn_abi.args[0].layout.ty.is_ref() {
+ // If this impl is not an inherent impl, get the trait it implements
+ if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id.unwrap()) {
+ // Transform the concrete self into a reference to a trait object
+ let existential_predicate = trait_ref.map_bound(|trait_ref| {
+ ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(
+ tcx, trait_ref,
+ ))
+ });
+ let existential_predicates = tcx.mk_poly_existential_predicates(&[ty::Binder::dummy(
+ existential_predicate.skip_binder(),
+ )]);
+ // Is the concrete self mutable?
+ let self_ty = if fn_abi.args[0].layout.ty.is_mutable_ptr() {
+ tcx.mk_mut_ref(
+ tcx.lifetimes.re_erased,
+ tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+ )
+ } else {
+ tcx.mk_imm_ref(
+ tcx.lifetimes.re_erased,
+ tcx.mk_dynamic(existential_predicates, tcx.lifetimes.re_erased, ty::Dyn),
+ )
+ };
+
+ // Replace the concrete self in an fn_abi clone by the reference to a trait object
+ let mut fn_abi = fn_abi.clone();
+ // HACK(rcvalle): It is okay to not replace or update the entire ArgAbi here because the
+ // other fields are never used.
+ fn_abi.args[0].layout.ty = self_ty;
+
+ return typeid_for_fnabi(tcx, &fn_abi, options);
+ }
+ }
+
+ typeid_for_fnabi(tcx, &fn_abi, options)
+}
diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs
index ee8832855..4cccc6398 100644
--- a/compiler/rustc_symbol_mangling/src/v0.rs
+++ b/compiler/rustc_symbol_mangling/src/v0.rs
@@ -433,7 +433,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
// Mangle all nominal types as paths.
ty::Adt(ty::AdtDef(Interned(&ty::AdtDefData { did: def_id, .. }, _)), substs)
| ty::FnDef(def_id, substs)
- | ty::Alias(_, ty::AliasTy { def_id, substs, .. })
+ | ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. })
| ty::Closure(def_id, substs)
| ty::Generator(def_id, substs, _) => {
self = self.print_def_path(def_id, substs)?;
@@ -482,6 +482,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
self = r.print(self)?;
}
+ ty::Alias(ty::Inherent, _) => bug!("symbol_names: unexpected inherent projection"),
ty::GeneratorWitness(_) => bug!("symbol_names: unexpected `GeneratorWitness`"),
ty::GeneratorWitnessMIR(..) => bug!("symbol_names: unexpected `GeneratorWitnessMIR`"),
}
@@ -731,7 +732,7 @@ impl<'tcx> Printer<'tcx> for &mut SymbolMangler<'tcx> {
fn path_crate(self, cnum: CrateNum) -> Result<Self::Path, Self::Error> {
self.push("C");
let stable_crate_id = self.tcx.def_path_hash(cnum.as_def_id()).stable_crate_id();
- self.push_disambiguator(stable_crate_id.to_u64());
+ self.push_disambiguator(stable_crate_id.as_u64());
let name = self.tcx.crate_name(cnum);
self.push_ident(name.as_str());
Ok(self)
diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml
index 4e7a8d166..dff22fad4 100644
--- a/compiler/rustc_target/Cargo.toml
+++ b/compiler/rustc_target/Cargo.toml
@@ -11,7 +11,6 @@ rustc_fs_util = { path = "../rustc_fs_util" }
rustc_abi = { path = "../rustc_abi" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_feature = { path = "../rustc_feature" }
-rustc_index = { path = "../rustc_index" }
rustc_macros = { path = "../rustc_macros" }
rustc_serialize = { path = "../rustc_serialize" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_target/src/abi/call/avr.rs b/compiler/rustc_target/src/abi/call/avr.rs
index e20f01355..b01dac8c7 100644
--- a/compiler/rustc_target/src/abi/call/avr.rs
+++ b/compiler/rustc_target/src/abi/call/avr.rs
@@ -10,7 +10,7 @@
//! > self-consistent and sensible LLVM IR generation, but does not
//! > conform to any particular ABI.
//! >
-//! > - Doxygen Doxumentation of `clang::DefaultABIInfo`
+//! > - Doxygen Documentation of `clang::DefaultABIInfo`
//!
//! This calling convention may not match AVR-GCC in all cases.
//!
diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs
index 57011aa8a..1ae11f567 100644
--- a/compiler/rustc_target/src/abi/call/mod.rs
+++ b/compiler/rustc_target/src/abi/call/mod.rs
@@ -28,7 +28,7 @@ mod x86;
mod x86_64;
mod x86_win64;
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub enum PassMode {
/// Ignore the argument.
///
@@ -65,7 +65,7 @@ mod attr_impl {
// The subset of llvm::Attribute needed for arguments, packed into a bitfield.
bitflags::bitflags! {
#[derive(Default, HashStable_Generic)]
- pub struct ArgAttribute: u16 {
+ pub struct ArgAttribute: u8 {
const NoAlias = 1 << 1;
const NoCapture = 1 << 2;
const NonNull = 1 << 3;
@@ -211,7 +211,7 @@ impl Uniform {
}
}
-#[derive(Clone, Copy, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct CastTarget {
pub prefix: [Option<Reg>; 8],
pub rest: Uniform,
@@ -458,7 +458,7 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
/// Information about how to pass an argument to,
/// or return a value from, a function, under some ABI.
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct ArgAbi<'a, Ty> {
pub layout: TyAndLayout<'a, Ty>,
pub mode: PassMode,
@@ -605,7 +605,7 @@ pub enum Conv {
///
/// I will do my best to describe this structure, but these
/// comments are reverse-engineered and may be inaccurate. -NDM
-#[derive(PartialEq, Eq, Hash, Debug, HashStable_Generic)]
+#[derive(Clone, PartialEq, Eq, Hash, Debug, HashStable_Generic)]
pub struct FnAbi<'a, Ty> {
/// The LLVM types of each argument.
pub args: Box<[ArgAbi<'a, Ty>]>,
diff --git a/compiler/rustc_target/src/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs
index 8d2e92cc7..589cd3cf9 100644
--- a/compiler/rustc_target/src/abi/mod.rs
+++ b/compiler/rustc_target/src/abi/mod.rs
@@ -124,6 +124,21 @@ impl<'a, Ty> TyAndLayout<'a, Ty> {
{
Ty::is_unit(self)
}
+
+ pub fn offset_of_subfield<C>(self, cx: &C, indices: impl Iterator<Item = usize>) -> Size
+ where
+ Ty: TyAbiInterface<'a, C>,
+ {
+ let mut layout = self;
+ let mut offset = Size::ZERO;
+
+ for index in indices {
+ offset += layout.fields.offset(index);
+ layout = layout.field(cx, index);
+ }
+
+ offset
+ }
}
impl<'a, Ty> TyAndLayout<'a, Ty> {
diff --git a/compiler/rustc_target/src/asm/loongarch.rs b/compiler/rustc_target/src/asm/loongarch.rs
new file mode 100644
index 000000000..9d1a4f3ee
--- /dev/null
+++ b/compiler/rustc_target/src/asm/loongarch.rs
@@ -0,0 +1,130 @@
+use super::{InlineAsmArch, InlineAsmType};
+use rustc_macros::HashStable_Generic;
+use rustc_span::Symbol;
+use std::fmt;
+
+def_reg_class! {
+ LoongArch LoongArchInlineAsmRegClass {
+ reg,
+ freg,
+ }
+}
+
+impl LoongArchInlineAsmRegClass {
+ pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] {
+ &[]
+ }
+
+ pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> {
+ None
+ }
+
+ pub fn suggest_modifier(
+ self,
+ _arch: InlineAsmArch,
+ _ty: InlineAsmType,
+ ) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> {
+ None
+ }
+
+ pub fn supported_types(
+ self,
+ _arch: InlineAsmArch,
+ ) -> &'static [(InlineAsmType, Option<Symbol>)] {
+ match self {
+ Self::reg => types! { _: I8, I16, I32, I64, F32, F64; },
+ Self::freg => types! { _: F32, F64; },
+ }
+ }
+}
+
+// The reserved registers are taken from <https://github.com/llvm/llvm-project/blob/main/llvm/lib/Target/LoongArch/LoongArchRegisterInfo.cpp#79>
+def_regs! {
+ LoongArch LoongArchInlineAsmReg LoongArchInlineAsmRegClass {
+ r1: reg = ["$r1","$ra"],
+ r4: reg = ["$r4","$a0"],
+ r5: reg = ["$r5","$a1"],
+ r6: reg = ["$r6","$a2"],
+ r7: reg = ["$r7","$a3"],
+ r8: reg = ["$r8","$a4"],
+ r9: reg = ["$r9","$a5"],
+ r10: reg = ["$r10","$a6"],
+ r11: reg = ["$r11","$a7"],
+ r12: reg = ["$r12","$t0"],
+ r13: reg = ["$r13","$t1"],
+ r14: reg = ["$r14","$t2"],
+ r15: reg = ["$r15","$t3"],
+ r16: reg = ["$r16","$t4"],
+ r17: reg = ["$r17","$t5"],
+ r18: reg = ["$r18","$t6"],
+ r19: reg = ["$r19","$t7"],
+ r20: reg = ["$r20","$t8"],
+ r23: reg = ["$r23","$s0"],
+ r24: reg = ["$r24","$s1"],
+ r25: reg = ["$r25","$s2"],
+ r26: reg = ["$r26","$s3"],
+ r27: reg = ["$r27","$s4"],
+ r28: reg = ["$r28","$s5"],
+ r29: reg = ["$r29","$s6"],
+ r30: reg = ["$r30","$s7"],
+ f0: freg = ["$f0","$fa0"],
+ f1: freg = ["$f1","$fa1"],
+ f2: freg = ["$f2","$fa2"],
+ f3: freg = ["$f3","$fa3"],
+ f4: freg = ["$f4","$fa4"],
+ f5: freg = ["$f5","$fa5"],
+ f6: freg = ["$f6","$fa6"],
+ f7: freg = ["$f7","$fa7"],
+ f8: freg = ["$f8","$ft0"],
+ f9: freg = ["$f9","$ft1"],
+ f10: freg = ["$f10","$ft2"],
+ f11: freg = ["$f11","$ft3"],
+ f12: freg = ["$f12","$ft4"],
+ f13: freg = ["$f13","$ft5"],
+ f14: freg = ["$f14","$ft6"],
+ f15: freg = ["$f15","$ft7"],
+ f16: freg = ["$f16","$ft8"],
+ f17: freg = ["$f17","$ft9"],
+ f18: freg = ["$f18","$ft10"],
+ f19: freg = ["$f19","$ft11"],
+ f20: freg = ["$f20","$ft12"],
+ f21: freg = ["$f21","$ft13"],
+ f22: freg = ["$f22","$ft14"],
+ f23: freg = ["$f23","$ft15"],
+ f24: freg = ["$f24","$fs0"],
+ f25: freg = ["$f25","$fs1"],
+ f26: freg = ["$f26","$fs2"],
+ f27: freg = ["$f27","$fs3"],
+ f28: freg = ["$f28","$fs4"],
+ f29: freg = ["$f29","$fs5"],
+ f30: freg = ["$f30","$fs6"],
+ f31: freg = ["$f31","$fs7"],
+ #error = ["$r0","$zero"] =>
+ "constant zero cannot be used as an operand for inline asm",
+ #error = ["$r2","$tp"] =>
+ "reserved for TLS",
+ #error = ["$r3","$sp"] =>
+ "the stack pointer cannot be used as an operand for inline asm",
+ #error = ["$r21"] =>
+ "reserved by the ABI",
+ #error = ["$r22","$fp"] =>
+ "the frame pointer cannot be used as an operand for inline asm",
+ #error = ["$r31","$s8"] =>
+ "$r31 is used internally by LLVM and cannot be used as an operand for inline asm",
+ }
+}
+
+impl LoongArchInlineAsmReg {
+ pub fn emit(
+ self,
+ out: &mut dyn fmt::Write,
+ _arch: InlineAsmArch,
+ _modifier: Option<char>,
+ ) -> fmt::Result {
+ out.write_str(self.name())
+ }
+}
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs
index 3f9c850b3..e60b8e78e 100644
--- a/compiler/rustc_target/src/asm/mod.rs
+++ b/compiler/rustc_target/src/asm/mod.rs
@@ -168,6 +168,7 @@ mod arm;
mod avr;
mod bpf;
mod hexagon;
+mod loongarch;
mod m68k;
mod mips;
mod msp430;
@@ -184,6 +185,7 @@ pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass};
pub use avr::{AvrInlineAsmReg, AvrInlineAsmRegClass};
pub use bpf::{BpfInlineAsmReg, BpfInlineAsmRegClass};
pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass};
+pub use loongarch::{LoongArchInlineAsmReg, LoongArchInlineAsmRegClass};
pub use m68k::{M68kInlineAsmReg, M68kInlineAsmRegClass};
pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass};
pub use msp430::{Msp430InlineAsmReg, Msp430InlineAsmRegClass};
@@ -205,6 +207,7 @@ pub enum InlineAsmArch {
RiscV64,
Nvptx64,
Hexagon,
+ LoongArch64,
Mips,
Mips64,
PowerPC,
@@ -234,6 +237,7 @@ impl FromStr for InlineAsmArch {
"powerpc" => Ok(Self::PowerPC),
"powerpc64" => Ok(Self::PowerPC64),
"hexagon" => Ok(Self::Hexagon),
+ "loongarch64" => Ok(Self::LoongArch64),
"mips" => Ok(Self::Mips),
"mips64" => Ok(Self::Mips64),
"s390x" => Ok(Self::S390x),
@@ -259,6 +263,7 @@ pub enum InlineAsmReg {
Nvptx(NvptxInlineAsmReg),
PowerPC(PowerPCInlineAsmReg),
Hexagon(HexagonInlineAsmReg),
+ LoongArch(LoongArchInlineAsmReg),
Mips(MipsInlineAsmReg),
S390x(S390xInlineAsmReg),
SpirV(SpirVInlineAsmReg),
@@ -280,6 +285,7 @@ impl InlineAsmReg {
Self::RiscV(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
+ Self::LoongArch(r) => r.name(),
Self::Mips(r) => r.name(),
Self::S390x(r) => r.name(),
Self::Bpf(r) => r.name(),
@@ -298,6 +304,7 @@ impl InlineAsmReg {
Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()),
Self::PowerPC(r) => InlineAsmRegClass::PowerPC(r.reg_class()),
Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()),
+ Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()),
Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()),
Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()),
Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()),
@@ -324,6 +331,7 @@ impl InlineAsmReg {
Self::PowerPC(PowerPCInlineAsmReg::parse(name)?)
}
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse(name)?),
+ InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmReg::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmReg::parse(name)?)
}
@@ -354,6 +362,9 @@ impl InlineAsmReg {
Self::RiscV(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::PowerPC(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Hexagon(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
+ Self::LoongArch(r) => {
+ r.validate(arch, reloc_model, target_features, target, is_clobber)
+ }
Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber),
@@ -379,6 +390,7 @@ impl InlineAsmReg {
Self::RiscV(r) => r.emit(out, arch, modifier),
Self::PowerPC(r) => r.emit(out, arch, modifier),
Self::Hexagon(r) => r.emit(out, arch, modifier),
+ Self::LoongArch(r) => r.emit(out, arch, modifier),
Self::Mips(r) => r.emit(out, arch, modifier),
Self::S390x(r) => r.emit(out, arch, modifier),
Self::Bpf(r) => r.emit(out, arch, modifier),
@@ -397,6 +409,7 @@ impl InlineAsmReg {
Self::RiscV(_) => cb(self),
Self::PowerPC(r) => r.overlapping_regs(|r| cb(Self::PowerPC(r))),
Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))),
+ Self::LoongArch(_) => cb(self),
Self::Mips(_) => cb(self),
Self::S390x(_) => cb(self),
Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))),
@@ -418,6 +431,7 @@ pub enum InlineAsmRegClass {
Nvptx(NvptxInlineAsmRegClass),
PowerPC(PowerPCInlineAsmRegClass),
Hexagon(HexagonInlineAsmRegClass),
+ LoongArch(LoongArchInlineAsmRegClass),
Mips(MipsInlineAsmRegClass),
S390x(S390xInlineAsmRegClass),
SpirV(SpirVInlineAsmRegClass),
@@ -440,6 +454,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.name(),
Self::PowerPC(r) => r.name(),
Self::Hexagon(r) => r.name(),
+ Self::LoongArch(r) => r.name(),
Self::Mips(r) => r.name(),
Self::S390x(r) => r.name(),
Self::SpirV(r) => r.name(),
@@ -464,6 +479,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx),
Self::PowerPC(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::PowerPC),
Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon),
+ Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch),
Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips),
Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x),
Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV),
@@ -495,6 +511,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.suggest_modifier(arch, ty),
Self::PowerPC(r) => r.suggest_modifier(arch, ty),
Self::Hexagon(r) => r.suggest_modifier(arch, ty),
+ Self::LoongArch(r) => r.suggest_modifier(arch, ty),
Self::Mips(r) => r.suggest_modifier(arch, ty),
Self::S390x(r) => r.suggest_modifier(arch, ty),
Self::SpirV(r) => r.suggest_modifier(arch, ty),
@@ -522,6 +539,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.default_modifier(arch),
Self::PowerPC(r) => r.default_modifier(arch),
Self::Hexagon(r) => r.default_modifier(arch),
+ Self::LoongArch(r) => r.default_modifier(arch),
Self::Mips(r) => r.default_modifier(arch),
Self::S390x(r) => r.default_modifier(arch),
Self::SpirV(r) => r.default_modifier(arch),
@@ -548,6 +566,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.supported_types(arch),
Self::PowerPC(r) => r.supported_types(arch),
Self::Hexagon(r) => r.supported_types(arch),
+ Self::LoongArch(r) => r.supported_types(arch),
Self::Mips(r) => r.supported_types(arch),
Self::S390x(r) => r.supported_types(arch),
Self::SpirV(r) => r.supported_types(arch),
@@ -575,6 +594,7 @@ impl InlineAsmRegClass {
Self::PowerPC(PowerPCInlineAsmRegClass::parse(name)?)
}
InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmRegClass::parse(name)?),
+ InlineAsmArch::LoongArch64 => Self::LoongArch(LoongArchInlineAsmRegClass::parse(name)?),
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
Self::Mips(MipsInlineAsmRegClass::parse(name)?)
}
@@ -601,6 +621,7 @@ impl InlineAsmRegClass {
Self::Nvptx(r) => r.valid_modifiers(arch),
Self::PowerPC(r) => r.valid_modifiers(arch),
Self::Hexagon(r) => r.valid_modifiers(arch),
+ Self::LoongArch(r) => r.valid_modifiers(arch),
Self::Mips(r) => r.valid_modifiers(arch),
Self::S390x(r) => r.valid_modifiers(arch),
Self::SpirV(r) => r.valid_modifiers(arch),
@@ -760,6 +781,11 @@ pub fn allocatable_registers(
hexagon::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
map
}
+ InlineAsmArch::LoongArch64 => {
+ let mut map = loongarch::regclass_map();
+ loongarch::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
+ map
+ }
InlineAsmArch::Mips | InlineAsmArch::Mips64 => {
let mut map = mips::regclass_map();
mips::fill_reg_map(arch, reloc_model, target_features, target, &mut map);
@@ -813,6 +839,7 @@ pub enum InlineAsmClobberAbi {
AArch64,
AArch64NoX18,
RiscV,
+ LoongArch,
}
impl InlineAsmClobberAbi {
@@ -854,6 +881,10 @@ impl InlineAsmClobberAbi {
"C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::RiscV),
_ => Err(&["C", "system", "efiapi"]),
},
+ InlineAsmArch::LoongArch64 => match name {
+ "C" | "system" => Ok(InlineAsmClobberAbi::LoongArch),
+ _ => Err(&["C", "system"]),
+ },
_ => Err(&[]),
}
}
@@ -996,6 +1027,21 @@ impl InlineAsmClobberAbi {
v24, v25, v26, v27, v28, v29, v30, v31,
}
},
+ InlineAsmClobberAbi::LoongArch => clobbered_regs! {
+ LoongArch LoongArchInlineAsmReg {
+ // ra
+ r1,
+ // a0-a7
+ r4, r5, r6, r7, r8, r9, r10, r11,
+ // t0-t8
+ r12, r13, r14, r15, r16, r17, r18, r19, r20,
+ // fa0-fa7
+ f0, f1, f2, f3, f4, f5, f6, f7,
+ // ft0-ft15
+ f8, f9, f10, f11, f12, f13, f14, f15,
+ f16, f17, f18, f19, f20, f21, f22, f23,
+ }
+ },
}
}
}
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
index b69ade7e4..9ac732351 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs
@@ -4,7 +4,7 @@ use crate::spec::{FramePointer, SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
let arch = Arch::Arm64;
let mut base = opts("macos", arch);
- base.cpu = "apple-a14".into();
+ base.cpu = "apple-m1".into();
base.max_atomic_width = Some(128);
// FIXME: The leak sanitizer currently fails the tests, see #88132.
diff --git a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
index 2b135b670..e2df7e0bd 100644
--- a/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/aarch64_apple_ios_macabi.rs
@@ -2,7 +2,7 @@ use super::apple_base::{opts, Arch};
use crate::spec::{Cc, FramePointer, LinkerFlavor, Lld, Target, TargetOptions};
pub fn target() -> Target {
- let llvm_target = "arm64-apple-ios-macabi";
+ let llvm_target = "arm64-apple-ios14.0-macabi";
let arch = Arch::Arm64_macabi;
let mut base = opts("ios", arch);
diff --git a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
index d0c950c2e..523eb6bd2 100644
--- a/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
+++ b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs
@@ -1,10 +1,15 @@
-use crate::spec::{Target, TargetOptions};
+use crate::spec::{SanitizerSet, Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_musl_base::opts();
base.max_atomic_width = Some(128);
base.supports_xray = true;
base.features = "+v8a".into();
+ base.supported_sanitizers = SanitizerSet::ADDRESS
+ | SanitizerSet::CFI
+ | SanitizerSet::LEAK
+ | SanitizerSet::MEMORY
+ | SanitizerSet::THREAD;
Target {
llvm_target: "aarch64-unknown-linux-musl".into(),
diff --git a/compiler/rustc_target/src/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs
index 5582d909f..eb3f66ac3 100644
--- a/compiler/rustc_target/src/spec/abi.rs
+++ b/compiler/rustc_target/src/spec/abi.rs
@@ -148,8 +148,9 @@ pub fn is_enabled(
pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
match name {
// Stable
- "Rust" | "C" | "cdecl" | "stdcall" | "fastcall" | "aapcs" | "win64" | "sysv64"
- | "system" | "efiapi" => Ok(()),
+ "Rust" | "C" | "C-unwind" | "cdecl" | "cdecl-unwind" | "stdcall" | "stdcall-unwind"
+ | "fastcall" | "fastcall-unwind" | "aapcs" | "aapcs-unwind" | "win64" | "win64-unwind"
+ | "sysv64" | "sysv64-unwind" | "system" | "system-unwind" | "efiapi" => Ok(()),
"rust-intrinsic" => Err(AbiDisabled::Unstable {
feature: sym::intrinsics,
explain: "intrinsics are subject to change",
@@ -162,10 +163,18 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
feature: sym::abi_vectorcall,
explain: "vectorcall is experimental and subject to change",
}),
+ "vectorcall-unwind" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_vectorcall,
+ explain: "vectorcall-unwind ABI is experimental and subject to change",
+ }),
"thiscall" => Err(AbiDisabled::Unstable {
feature: sym::abi_thiscall,
explain: "thiscall is experimental and subject to change",
}),
+ "thiscall-unwind" => Err(AbiDisabled::Unstable {
+ feature: sym::abi_thiscall,
+ explain: "thiscall-unwind ABI is experimental and subject to change",
+ }),
"rust-call" => Err(AbiDisabled::Unstable {
feature: sym::unboxed_closures,
explain: "rust-call ABI is subject to change",
@@ -202,46 +211,6 @@ pub fn is_stable(name: &str) -> Result<(), AbiDisabled> {
feature: sym::abi_c_cmse_nonsecure_call,
explain: "C-cmse-nonsecure-call ABI is experimental and subject to change",
}),
- "C-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "C-unwind ABI is experimental and subject to change",
- }),
- "stdcall-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "stdcall-unwind ABI is experimental and subject to change",
- }),
- "system-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "system-unwind ABI is experimental and subject to change",
- }),
- "thiscall-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "thiscall-unwind ABI is experimental and subject to change",
- }),
- "cdecl-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "cdecl-unwind ABI is experimental and subject to change",
- }),
- "fastcall-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "fastcall-unwind ABI is experimental and subject to change",
- }),
- "vectorcall-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "vectorcall-unwind ABI is experimental and subject to change",
- }),
- "aapcs-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "aapcs-unwind ABI is experimental and subject to change",
- }),
- "win64-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "win64-unwind ABI is experimental and subject to change",
- }),
- "sysv64-unwind" => Err(AbiDisabled::Unstable {
- feature: sym::c_unwind,
- explain: "sysv64-unwind ABI is experimental and subject to change",
- }),
"wasm" => Err(AbiDisabled::Unstable {
feature: sym::wasm_abi,
explain: "wasm ABI is experimental and subject to change",
diff --git a/compiler/rustc_target/src/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs
index 5c6dcc0ab..ff2246318 100644
--- a/compiler/rustc_target/src/spec/apple_base.rs
+++ b/compiler/rustc_target/src/spec/apple_base.rs
@@ -1,7 +1,7 @@
use std::{borrow::Cow, env};
use crate::spec::{cvs, Cc, DebuginfoKind, FramePointer, LinkArgs};
-use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, TargetOptions};
+use crate::spec::{LinkerFlavor, Lld, SplitDebuginfo, StaticCow, Target, TargetOptions};
#[cfg(test)]
#[path = "apple/tests.rs"]
@@ -19,6 +19,7 @@ pub enum Arch {
I386,
I686,
X86_64,
+ X86_64h,
X86_64_sim,
X86_64_macabi,
Arm64_macabi,
@@ -36,6 +37,7 @@ impl Arch {
I386 => "i386",
I686 => "i686",
X86_64 | X86_64_sim | X86_64_macabi => "x86_64",
+ X86_64h => "x86_64h",
}
}
@@ -44,13 +46,13 @@ impl Arch {
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",
+ X86_64 | X86_64_sim | X86_64_macabi | X86_64h => "x86_64",
})
}
fn target_abi(self) -> &'static str {
match self {
- Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 => "",
+ Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64h => "",
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...
@@ -67,6 +69,10 @@ impl Arch {
Arm64_32 => "apple-s4",
I386 | I686 => "yonah",
X86_64 | X86_64_sim => "core2",
+ // Note: `core-avx2` is slightly more advanced than `x86_64h`, see
+ // comments (and disabled features) in `x86_64h_apple_darwin` for
+ // details.
+ X86_64h => "core-avx2",
X86_64_macabi => "core2",
Arm64_macabi => "apple-a12",
Arm64_sim => "apple-a12",
@@ -173,21 +179,43 @@ pub fn opts(os: &'static str, arch: Arch) -> TargetOptions {
}
}
-fn deployment_target(var_name: &str) -> Option<(u32, u32)> {
- let deployment_target = env::var(var_name).ok();
- deployment_target
- .as_ref()
- .and_then(|s| s.split_once('.'))
- .and_then(|(a, b)| a.parse::<u32>().and_then(|a| b.parse::<u32>().map(|b| (a, b))).ok())
+pub fn deployment_target(target: &Target) -> Option<String> {
+ let (major, minor) = match &*target.os {
+ "macos" => {
+ // This does not need to be specific. It just needs to handle x86 vs M1.
+ let arch = if target.arch == "x86" || target.arch == "x86_64" { X86_64 } else { Arm64 };
+ macos_deployment_target(arch)
+ }
+ "ios" => ios_deployment_target(),
+ "watchos" => watchos_deployment_target(),
+ "tvos" => tvos_deployment_target(),
+ _ => return None,
+ };
+
+ Some(format!("{major}.{minor}"))
+}
+
+fn from_set_deployment_target(var_name: &str) -> Option<(u32, u32)> {
+ let deployment_target = env::var(var_name).ok()?;
+ let (unparsed_major, unparsed_minor) = deployment_target.split_once('.')?;
+ let (major, minor) = (unparsed_major.parse().ok()?, unparsed_minor.parse().ok()?);
+
+ Some((major, minor))
}
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) }
+ match arch {
+ // Note: Arm64_sim is not included since macOS has no simulator.
+ Arm64 | Arm64_macabi => (11, 0),
+ // x86_64h-apple-darwin only supports macOS 10.8 and later
+ X86_64h => (10, 8),
+ _ => (10, 7),
+ }
}
fn macos_deployment_target(arch: Arch) -> (u32, u32) {
- deployment_target("MACOSX_DEPLOYMENT_TARGET")
+ // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+ from_set_deployment_target("MACOSX_DEPLOYMENT_TARGET")
.unwrap_or_else(|| macos_default_deployment_target(arch))
}
@@ -227,7 +255,7 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]>
// of the linking environment that's wrong and reversed.
match arch {
Armv7 | Armv7k | Armv7s | Arm64 | Arm64_32 | I386 | I686 | X86_64 | X86_64_sim
- | Arm64_sim => {
+ | X86_64h | Arm64_sim => {
cvs!["MACOSX_DEPLOYMENT_TARGET"]
}
X86_64_macabi | Arm64_macabi => cvs!["IPHONEOS_DEPLOYMENT_TARGET"],
@@ -236,7 +264,8 @@ fn link_env_remove(arch: Arch, os: &'static str) -> StaticCow<[StaticCow<str>]>
}
fn ios_deployment_target() -> (u32, u32) {
- deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+ // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+ from_set_deployment_target("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}
pub fn ios_llvm_target(arch: Arch) -> String {
@@ -261,7 +290,8 @@ pub fn ios_sim_llvm_target(arch: Arch) -> String {
}
fn tvos_deployment_target() -> (u32, u32) {
- deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
+ // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+ from_set_deployment_target("TVOS_DEPLOYMENT_TARGET").unwrap_or((7, 0))
}
fn tvos_lld_platform_version() -> String {
@@ -270,7 +300,8 @@ fn tvos_lld_platform_version() -> String {
}
fn watchos_deployment_target() -> (u32, u32) {
- deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
+ // If you are looking for the default deployment target, prefer `rustc --print deployment-target`.
+ from_set_deployment_target("WATCHOS_DEPLOYMENT_TARGET").unwrap_or((5, 0))
}
fn watchos_lld_platform_version() -> String {
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
index f6f46aac4..5632bcfce 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC and Clang default to 8 for arm-none here
c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
index 9608efe8b..2815de358 100644
--- a/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs
@@ -17,7 +17,7 @@ pub fn target() -> Target {
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
features: "+vfp3,-d32,-fp16".into(),
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC and Clang default to 8 for arm-none here
c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs b/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
index ebd2cca25..e2c0808f1 100644
--- a/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7_sony_vita_newlibeabihf.rs
@@ -9,7 +9,7 @@ pub fn target() -> Target {
let pre_link_args = TargetOptions::link_args(LinkerFlavor::Gnu(Cc::Yes, Lld::No), &["-Wl,-q"]);
Target {
- llvm_target: "armv7a-vita-newlibeabihf".into(),
+ llvm_target: "armv7a-vita-eabihf".into(),
pointer_width: 32,
data_layout: "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64".into(),
arch: "arm".into(),
@@ -33,7 +33,7 @@ pub fn target() -> Target {
pre_link_args,
exe_suffix: ".elf".into(),
panic_strategy: PanicStrategy::Abort,
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
..Default::default()
},
}
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
index 5225abf44..74905ed5a 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs
@@ -15,7 +15,7 @@ pub fn target() -> Target {
linker: Some("rust-lld".into()),
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC and Clang default to 8 for arm-none here
c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
index 9a35e0461..516b3f5c1 100644
--- a/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
+++ b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs
@@ -16,7 +16,7 @@ pub fn target() -> Target {
relocation_model: RelocModel::Static,
panic_strategy: PanicStrategy::Abort,
features: "+vfp3,-d32,-fp16".into(),
- max_atomic_width: Some(32),
+ max_atomic_width: Some(64),
emit_debug_gdb_scripts: false,
// GCC and Clang default to 8 for arm-none here
c_enum_min_bits: Some(8),
diff --git a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
index ebd74012d..9bcd56bed 100644
--- a/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
+++ b/compiler/rustc_target/src/spec/m68k_unknown_linux_gnu.rs
@@ -3,6 +3,7 @@ use crate::spec::{Target, TargetOptions};
pub fn target() -> Target {
let mut base = super::linux_gnu_base::opts();
+ base.cpu = "M68020".into();
base.max_atomic_width = Some(32);
Target {
diff --git a/compiler/rustc_target/src/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs
index 4e5a821f0..ba4b89c9e 100644
--- a/compiler/rustc_target/src/spec/mod.rs
+++ b/compiler/rustc_target/src/spec/mod.rs
@@ -60,6 +60,7 @@ pub mod crt_objects;
mod aix_base;
mod android_base;
mod apple_base;
+pub use apple_base::deployment_target as current_apple_deployment_target;
mod avr_gnu_base;
mod bpf_base;
mod dragonfly_base;
@@ -1112,6 +1113,7 @@ supported_targets! {
("aarch64-apple-darwin", aarch64_apple_darwin),
("x86_64-apple-darwin", x86_64_apple_darwin),
+ ("x86_64h-apple-darwin", x86_64h_apple_darwin),
("i686-apple-darwin", i686_apple_darwin),
// FIXME(#106649): Remove aarch64-fuchsia in favor of aarch64-unknown-fuchsia
@@ -2285,13 +2287,13 @@ impl Target {
}
}
} );
- ($key_name:ident, falliable_list) => ( {
+ ($key_name:ident, fallible_list) => ( {
let name = (stringify!($key_name)).replace("_", "-");
obj.remove(&name).and_then(|j| {
if let Some(v) = j.as_array() {
match v.iter().map(|a| FromStr::from_str(a.as_str().unwrap())).collect() {
Ok(l) => { base.$key_name = l },
- // FIXME: `falliable_list` can't re-use the `key!` macro for list
+ // FIXME: `fallible_list` can't re-use the `key!` macro for list
// elements and the error messages from that macro, so it has a bad
// generic message instead
Err(_) => return Some(Err(
@@ -2610,7 +2612,7 @@ impl Target {
key!(has_thumb_interworking, bool);
key!(debuginfo_kind, DebuginfoKind)?;
key!(split_debuginfo, SplitDebuginfo)?;
- key!(supported_split_debuginfo, falliable_list)?;
+ key!(supported_split_debuginfo, fallible_list)?;
key!(supported_sanitizers, SanitizerSet)?;
key!(default_adjusted_cabi, Option<Abi>)?;
key!(generate_arange_section, bool);
diff --git a/compiler/rustc_target/src/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs
index 4dcf47fe4..2220b9326 100644
--- a/compiler/rustc_target/src/spec/thumb_base.rs
+++ b/compiler/rustc_target/src/spec/thumb_base.rs
@@ -12,7 +12,7 @@
//
// We have opted for these instead of one target per processor (e.g., `cortex-m0`, `cortex-m3`,
// etc) because the differences between some processors like the cortex-m0 and cortex-m1 are almost
-// non-existent from the POV of codegen so it doesn't make sense to have separate targets for them.
+// nonexistent from the POV of codegen so it doesn't make sense to have separate targets for them.
// And if differences exist between two processors under the same target, rustc flags can be used to
// optimize for one processor or the other.
//
diff --git a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
index 5a3e2a79b..9f3b0fab6 100644
--- a/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
+++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs
@@ -2,7 +2,7 @@ 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-ios-macabi";
+ let llvm_target = "x86_64-apple-ios14.0-macabi";
let arch = Arch::X86_64_macabi;
let mut base = opts("ios", arch);
diff --git a/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs
new file mode 100644
index 000000000..54f7490b2
--- /dev/null
+++ b/compiler/rustc_target/src/spec/x86_64h_apple_darwin.rs
@@ -0,0 +1,44 @@
+use super::apple_base::{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 = Arch::X86_64h;
+ let mut base = opts("macos", arch);
+ base.max_atomic_width = Some(128);
+ base.frame_pointer = FramePointer::Always;
+ base.add_pre_link_args(LinkerFlavor::Darwin(Cc::Yes, Lld::No), &["-m64"]);
+ base.stack_probes = StackProbeType::X86;
+ base.supported_sanitizers =
+ SanitizerSet::ADDRESS | SanitizerSet::CFI | SanitizerSet::LEAK | SanitizerSet::THREAD;
+
+ // x86_64h is core2-avx without a few of the features which would otherwise
+ // be guaranteed, so we need to disable those. This imitates clang's logic:
+ // - https://github.com/llvm/llvm-project/blob/bd1f7c417/clang/lib/Driver/ToolChains/Arch/X86.cpp#L77-L78
+ // - https://github.com/llvm/llvm-project/blob/bd1f7c417/clang/lib/Driver/ToolChains/Arch/X86.cpp#L133-L141
+ //
+ // FIXME: Sadly, turning these off here disables them in such a way that they
+ // aren't re-enabled by `-Ctarget-cpu=native` (on a machine that has them).
+ // It would be nice if this were not the case, but fixing it seems tricky
+ // (and given that the main use-case for this target is for use in universal
+ // binaries, probably not that important).
+ base.features = "-rdrnd,-aes,-pclmul,-rtm,-fsgsbase".into();
+ // Double-check that the `cpu` is what we expect (if it's not the list above
+ // may need updating).
+ assert_eq!(
+ base.cpu, "core-avx2",
+ "you need to adjust the feature list in x86_64h-apple-darwin if you change this",
+ );
+
+ Target {
+ // 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.target_arch(),
+ options: TargetOptions { mcount: "\u{1}mcount".into(), ..base },
+ }
+}
diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml
index d3eba43b4..83605627d 100644
--- a/compiler/rustc_trait_selection/Cargo.toml
+++ b/compiler/rustc_trait_selection/Cargo.toml
@@ -14,6 +14,7 @@ rustc_ast = { path = "../rustc_ast" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_index = { path = "../rustc_index" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
@@ -24,4 +25,3 @@ rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
rustc_transmute = { path = "../rustc_transmute", features = ["rustc"] }
smallvec = { version = "1.8.1", features = ["union", "may_dangle"] }
-itertools = "0.10.1"
diff --git a/compiler/rustc_trait_selection/messages.ftl b/compiler/rustc_trait_selection/messages.ftl
index 14eb4a550..217ba71b6 100644
--- a/compiler/rustc_trait_selection/messages.ftl
+++ b/compiler/rustc_trait_selection/messages.ftl
@@ -1,17 +1,13 @@
trait_selection_dump_vtable_entries = vtable entries for `{$trait_ref}`: {$entries}
-trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
-
trait_selection_empty_on_clause_in_rustc_on_unimplemented = empty `on`-clause in `#[rustc_on_unimplemented]`
.label = empty on-clause here
+trait_selection_inherent_projection_normalization_overflow = overflow evaluating associated type `{$ty}`
+
trait_selection_invalid_on_clause_in_rustc_on_unimplemented = invalid `on`-clause in `#[rustc_on_unimplemented]`
.label = invalid on-clause here
-trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
- .label = expected value here
- .note = eg `#[rustc_on_unimplemented(message="foo")]`
-
trait_selection_negative_positive_conflict = found both positive and negative implementation of trait `{$trait_desc}`{$self_desc ->
[none] {""}
*[default] {" "}for type `{$self_desc}`
@@ -20,3 +16,9 @@ trait_selection_negative_positive_conflict = found both positive and negative im
.negative_implementation_in_crate = negative implementation in crate `{$negative_impl_cname}`
.positive_implementation_here = positive implementation here
.positive_implementation_in_crate = positive implementation in crate `{$positive_impl_cname}`
+
+trait_selection_no_value_in_rustc_on_unimplemented = this attribute must have a valid value
+ .label = expected value here
+ .note = eg `#[rustc_on_unimplemented(message="foo")]`
+
+trait_selection_unable_to_construct_constant_value = unable to construct a constant value for the unevaluated constant {$unevaluated}
diff --git a/compiler/rustc_trait_selection/src/errors.rs b/compiler/rustc_trait_selection/src/errors.rs
index df7c4df18..54e22cc3d 100644
--- a/compiler/rustc_trait_selection/src/errors.rs
+++ b/compiler/rustc_trait_selection/src/errors.rs
@@ -89,3 +89,11 @@ impl IntoDiagnostic<'_> for NegativePositiveConflict<'_> {
diag
}
}
+
+#[derive(Diagnostic)]
+#[diag(trait_selection_inherent_projection_normalization_overflow)]
+pub struct InherentProjectionNormalizationOverflow {
+ #[primary_span]
+ pub span: Span,
+ pub ty: String,
+}
diff --git a/compiler/rustc_trait_selection/src/infer.rs b/compiler/rustc_trait_selection/src/infer.rs
index 911cc0b88..312bd3817 100644
--- a/compiler/rustc_trait_selection/src/infer.rs
+++ b/compiler/rustc_trait_selection/src/infer.rs
@@ -5,7 +5,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::arena::ArenaAllocatable;
use rustc_middle::infer::canonical::{Canonical, CanonicalQueryResponse, QueryResponse};
-use rustc_middle::traits::query::Fallible;
+use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::{self, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_middle::ty::{GenericArg, ToPredicate};
use rustc_span::DUMMY_SP;
@@ -41,7 +41,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
fn type_is_copy_modulo_regions(&self, param_env: ty::ParamEnv<'tcx>, ty: Ty<'tcx>) -> bool {
let ty = self.resolve_vars_if_possible(ty);
- if !(param_env, ty).needs_infer() {
+ if !(param_env, ty).has_infer() {
return ty.is_copy_modulo_regions(self.tcx, param_env);
}
@@ -66,7 +66,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
params: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
param_env: ty::ParamEnv<'tcx>,
) -> traits::EvaluationResult {
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, params);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, params);
let obligation = traits::Obligation {
cause: traits::ObligationCause::dummy(),
@@ -82,8 +82,8 @@ pub trait InferCtxtBuilderExt<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
+ operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
+ ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
where
K: TypeFoldable<TyCtxt<'tcx>>,
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
@@ -110,8 +110,8 @@ impl<'tcx> InferCtxtBuilderExt<'tcx> for InferCtxtBuilder<'tcx> {
fn enter_canonical_trait_query<K, R>(
&mut self,
canonical_key: &Canonical<'tcx, K>,
- operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Fallible<R>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, R>>
+ operation: impl FnOnce(&ObligationCtxt<'_, 'tcx>, K) -> Result<R, NoSolution>,
+ ) -> Result<CanonicalQueryResponse<'tcx, R>, NoSolution>
where
K: TypeFoldable<TyCtxt<'tcx>>,
R: Debug + TypeFoldable<TyCtxt<'tcx>>,
diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs
index f866cb016..ed3994be9 100644
--- a/compiler/rustc_trait_selection/src/lib.rs
+++ b/compiler/rustc_trait_selection/src/lib.rs
@@ -37,7 +37,7 @@ extern crate rustc_middle;
extern crate smallvec;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
+use rustc_fluent_macro::fluent_messages;
pub mod errors;
pub mod infer;
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
index 10d817f75..f32ff0442 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs
@@ -2,12 +2,12 @@
use super::search_graph::OverflowHandler;
use super::{EvalCtxt, SolverMode};
-use crate::solve::CanonicalResponseExt;
use crate::traits::coherence;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir::def_id::DefId;
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::util::elaborate;
+use rustc_infer::traits::Reveal;
use rustc_middle::traits::solve::{CanonicalResponse, Certainty, Goal, MaybeCause, QueryResult};
use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::TypeFoldable;
@@ -51,7 +51,7 @@ pub(super) enum CandidateSource {
BuiltinImpl,
/// An assumption from the environment.
///
- /// More precicely we've used the `n-th` assumption in the `param_env`.
+ /// More precisely we've used the `n-th` assumption in the `param_env`.
///
/// ## Examples
///
@@ -87,7 +87,9 @@ pub(super) enum CandidateSource {
}
/// Methods used to assemble candidates for either trait or projection goals.
-pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
+pub(super) trait GoalKind<'tcx>:
+ TypeFoldable<TyCtxt<'tcx>> + Copy + Eq + std::fmt::Display
+{
fn self_ty(self) -> Ty<'tcx>;
fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>;
@@ -96,6 +98,17 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId;
+ // Try equating an assumption predicate against a goal's predicate. If it
+ // holds, then execute the `then` callback, which should do any additional
+ // work, then produce a response (typically by executing
+ // [`EvalCtxt::evaluate_added_goals_and_make_canonical_response`]).
+ fn probe_and_match_goal_against_assumption(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ assumption: ty::Predicate<'tcx>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
+ ) -> QueryResult<'tcx>;
+
// Consider a clause, which consists of a "assumption" and some "requirements",
// to satisfy a goal. If the requirements hold, then attempt to satisfy our
// goal by equating it with the assumption.
@@ -104,7 +117,26 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
- ) -> QueryResult<'tcx>;
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ ecx.add_goals(requirements);
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
+
+ /// Consider a bound originating from the item bounds of an alias. For this we
+ /// require that the well-formed requirements of the self type of the goal
+ /// are "satisfied from the param-env".
+ /// See [`EvalCtxt::validate_alias_bound_self_from_param_env`].
+ fn consider_alias_bound_candidate(
+ ecx: &mut EvalCtxt<'_, 'tcx>,
+ goal: Goal<'tcx, Self>,
+ assumption: ty::Predicate<'tcx>,
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ ecx.validate_alias_bound_self_from_param_env(goal)
+ })
+ }
// Consider a clause specifically for a `dyn Trait` self type. This requires
// additionally checking all of the supertraits and object bounds to hold,
@@ -113,7 +145,25 @@ pub(super) trait GoalKind<'tcx>: TypeFoldable<TyCtxt<'tcx>> + Copy + Eq {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- ) -> QueryResult<'tcx>;
+ ) -> QueryResult<'tcx> {
+ Self::probe_and_match_goal_against_assumption(ecx, goal, assumption, |ecx| {
+ let tcx = ecx.tcx();
+ let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
+ bug!("expected object type in `consider_object_bound_candidate`");
+ };
+ ecx.add_goals(
+ structural_traits::predicates_for_object_candidate(
+ &ecx,
+ goal.param_env,
+ goal.predicate.trait_ref(tcx),
+ bounds,
+ )
+ .into_iter()
+ .map(|pred| goal.with(tcx, pred)),
+ );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ })
+ }
fn consider_impl_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
@@ -241,7 +291,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// HACK: `_: Trait` is ambiguous, because it may be satisfied via a builtin rule,
// object bound, alias bound, etc. We are unable to determine this until we can at
- // least structually resolve the type one layer.
+ // least structurally resolve the type one layer.
if goal.predicate.self_ty().is_ty_var() {
return vec![Candidate {
source: CandidateSource::BuiltinImpl,
@@ -282,8 +332,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
candidates: &mut Vec<Candidate<'tcx>>,
) {
let tcx = self.tcx();
- // FIXME: We also have to normalize opaque types, not sure where to best fit that in.
- let &ty::Alias(ty::Projection, projection_ty) = goal.predicate.self_ty().kind() else {
+ let &ty::Alias(_, projection_ty) = goal.predicate.self_ty().kind() else {
return
};
@@ -305,8 +354,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}),
);
ecx.add_goal(normalizes_to_goal);
- let _ = ecx.try_evaluate_added_goals()?;
+ let _ = ecx.try_evaluate_added_goals().inspect_err(|_| {
+ debug!("self type normalization failed");
+ })?;
let normalized_ty = ecx.resolve_vars_if_possible(normalized_ty);
+ debug!(?normalized_ty, "self type normalized");
// NOTE: Alternatively we could call `evaluate_goal` here and only
// have a `Normalized` candidate. This doesn't work as long as we
// use `CandidateSource` in winnowing.
@@ -455,15 +507,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| ty::Param(_)
| ty::Placeholder(..)
| ty::Infer(ty::IntVar(_) | ty::FloatVar(_))
+ | ty::Alias(ty::Inherent, _)
| ty::Error(_) => return,
ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_))
| ty::Bound(..) => bug!("unexpected self type for `{goal:?}`"),
- ty::Alias(_, alias_ty) => alias_ty,
+ // Excluding IATs here as they don't have meaningful item bounds.
+ ty::Alias(ty::Projection | ty::Opaque, alias_ty) => alias_ty,
};
for assumption in self.tcx().item_bounds(alias_ty.def_id).subst(self.tcx(), alias_ty.substs)
{
- match G::consider_implied_clause(self, goal, assumption, []) {
+ match G::consider_alias_bound_candidate(self, goal, assumption) {
Ok(result) => {
candidates.push(Candidate { source: CandidateSource::AliasBound, result })
}
@@ -472,6 +526,105 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
}
}
+ /// Check that we are allowed to use an alias bound originating from the self
+ /// type of this goal. This means something different depending on the self type's
+ /// alias kind.
+ ///
+ /// * Projection: Given a goal with a self type such as `<Ty as Trait>::Assoc`,
+ /// we require that the bound `Ty: Trait` can be proven using either a nested alias
+ /// bound candidate, or a param-env candidate.
+ ///
+ /// * Opaque: The param-env must be in `Reveal::UserFacing` mode. Otherwise,
+ /// the goal should be proven by using the hidden type instead.
+ #[instrument(level = "debug", skip(self), ret)]
+ pub(super) fn validate_alias_bound_self_from_param_env<G: GoalKind<'tcx>>(
+ &mut self,
+ goal: Goal<'tcx, G>,
+ ) -> QueryResult<'tcx> {
+ match *goal.predicate.self_ty().kind() {
+ ty::Alias(ty::Projection, projection_ty) => {
+ let mut param_env_candidates = vec![];
+ let self_trait_ref = projection_ty.trait_ref(self.tcx());
+
+ if self_trait_ref.self_ty().is_ty_var() {
+ return self
+ .evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+ }
+
+ let trait_goal: Goal<'_, ty::TraitPredicate<'tcx>> = goal.with(
+ self.tcx(),
+ ty::TraitPredicate {
+ trait_ref: self_trait_ref,
+ constness: ty::BoundConstness::NotConst,
+ polarity: ty::ImplPolarity::Positive,
+ },
+ );
+
+ self.assemble_param_env_candidates(trait_goal, &mut param_env_candidates);
+ // FIXME: We probably need some sort of recursion depth check here.
+ // Can't come up with an example yet, though, and the worst case
+ // we can have is a compiler stack overflow...
+ self.assemble_alias_bound_candidates(trait_goal, &mut param_env_candidates);
+
+ // FIXME: We must also consider alias-bound candidates for a peculiar
+ // class of built-in candidates that I'll call "defaulted" built-ins.
+ //
+ // For example, we always know that `T: Pointee` is implemented, but
+ // we do not always know what `<T as Pointee>::Metadata` actually is,
+ // similar to if we had a user-defined impl with a `default type ...`.
+ // For these traits, since we're not able to always normalize their
+ // associated types to a concrete type, we must consider their alias bounds
+ // instead, so we can prove bounds such as `<T as Pointee>::Metadata: Copy`.
+ self.assemble_alias_bound_candidates_for_builtin_impl_default_items(
+ trait_goal,
+ &mut param_env_candidates,
+ );
+
+ self.merge_candidates(param_env_candidates)
+ }
+ ty::Alias(ty::Opaque, _opaque_ty) => match goal.param_env.reveal() {
+ Reveal::UserFacing => {
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ Reveal::All => return Err(NoSolution),
+ },
+ _ => bug!("only expected to be called on alias tys"),
+ }
+ }
+
+ /// Assemble a subset of builtin impl candidates for a class of candidates called
+ /// "defaulted" built-in traits.
+ ///
+ /// For example, we always know that `T: Pointee` is implemented, but we do not
+ /// always know what `<T as Pointee>::Metadata` actually is! See the comment in
+ /// [`EvalCtxt::validate_alias_bound_self_from_param_env`] for more detail.
+ #[instrument(level = "debug", skip_all)]
+ fn assemble_alias_bound_candidates_for_builtin_impl_default_items<G: GoalKind<'tcx>>(
+ &mut self,
+ goal: Goal<'tcx, G>,
+ candidates: &mut Vec<Candidate<'tcx>>,
+ ) {
+ let lang_items = self.tcx().lang_items();
+ let trait_def_id = goal.predicate.trait_def_id(self.tcx());
+
+ // You probably shouldn't add anything to this list unless you
+ // know what you're doing.
+ let result = if lang_items.pointee_trait() == Some(trait_def_id) {
+ G::consider_builtin_pointee_candidate(self, goal)
+ } else if lang_items.discriminant_kind_trait() == Some(trait_def_id) {
+ G::consider_builtin_discriminant_kind_candidate(self, goal)
+ } else {
+ Err(NoSolution)
+ };
+
+ match result {
+ Ok(result) => {
+ candidates.push(Candidate { source: CandidateSource::BuiltinImpl, result })
+ }
+ Err(NoSolution) => (),
+ }
+ }
+
#[instrument(level = "debug", skip_all)]
fn assemble_object_bound_candidates<G: GoalKind<'tcx>>(
&mut self,
@@ -590,13 +743,18 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
SolverMode::Normal => {
let param_env_responses = candidates
.iter()
- .filter(|c| matches!(c.source, CandidateSource::ParamEnv(_)))
+ .filter(|c| {
+ matches!(
+ c.source,
+ CandidateSource::ParamEnv(_) | CandidateSource::AliasBound
+ )
+ })
.map(|c| c.result)
.collect::<Vec<_>>();
if let Some(result) = self.try_merge_responses(&param_env_responses) {
- if result.has_only_region_constraints() {
- return Ok(result);
- }
+ // We strongly prefer alias and param-env bounds here, even if they affect inference.
+ // See https://github.com/rust-lang/trait-system-refactor-initiative/issues/11.
+ return Ok(result);
}
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
index 1a566e87d..0ede32c75 100644
--- a/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
+++ b/compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs
@@ -33,7 +33,7 @@ pub(in crate::solve) fn instantiate_constituent_tys_for_auto_trait<'tcx>(
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..)
| ty::Infer(_) => {
@@ -91,14 +91,15 @@ pub(in crate::solve) fn replace_erased_lifetimes_with_bound_vars<'tcx>(
) -> ty::Binder<'tcx, Ty<'tcx>> {
debug_assert!(!ty.has_late_bound_regions());
let mut counter = 0;
- let ty = tcx.fold_regions(ty, |mut r, current_depth| {
- if let ty::ReErased = r.kind() {
+ let ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
+ ty::ReErased => {
let br =
ty::BoundRegion { var: ty::BoundVar::from_u32(counter), kind: ty::BrAnon(None) };
counter += 1;
- r = tcx.mk_re_late_bound(current_depth, br);
+ tcx.mk_re_late_bound(current_depth, br)
}
- r
+ // All free regions should be erased here.
+ r => bug!("unexpected region: {r:?}"),
});
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
(0..counter).map(|_| ty::BoundVariableKind::Region(ty::BrAnon(None))),
diff --git a/compiler/rustc_trait_selection/src/solve/canonicalize.rs b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
index 976849696..ff4bff10c 100644
--- a/compiler/rustc_trait_selection/src/solve/canonicalize.rs
+++ b/compiler/rustc_trait_selection/src/solve/canonicalize.rs
@@ -69,7 +69,7 @@ impl<'a, 'tcx> Canonicalizer<'a, 'tcx> {
};
let value = value.fold_with(&mut canonicalizer);
- assert!(!value.needs_infer());
+ assert!(!value.has_infer());
assert!(!value.has_placeholders());
let (max_universe, variables) = canonicalizer.finalize();
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
index c29b5b04e..f91c67277 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt.rs
@@ -1,14 +1,19 @@
-use rustc_hir::def_id::DefId;
+use rustc_hir::def_id::{DefId, LocalDefId};
use rustc_infer::infer::at::ToTrace;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use rustc_infer::infer::{
- DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, TyCtxtInferExt,
+ DefineOpaqueTypes, InferCtxt, InferOk, LateBoundRegionConversionTime, RegionVariableOrigin,
+ TyCtxtInferExt,
};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::ObligationCause;
use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind};
-use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{
+ CanonicalInput, CanonicalResponse, Certainty, MaybeCause, PredefinedOpaques,
+ PredefinedOpaquesData, QueryResult,
+};
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::{
self, Ty, TyCtxt, TypeFoldable, TypeSuperVisitable, TypeVisitable, TypeVisitableExt,
TypeVisitor,
@@ -43,6 +48,9 @@ pub struct EvalCtxt<'a, 'tcx> {
infcx: &'a InferCtxt<'tcx>,
pub(super) var_values: CanonicalVarValues<'tcx>,
+
+ predefined_opaques_in_body: PredefinedOpaques<'tcx>,
+
/// The highest universe index nameable by the caller.
///
/// When we enter a new binder inside of the query we create new universes
@@ -57,6 +65,14 @@ pub struct EvalCtxt<'a, 'tcx> {
pub(super) search_graph: &'a mut SearchGraph<'tcx>,
pub(super) nested_goals: NestedGoals<'tcx>,
+
+ // Has this `EvalCtxt` errored out with `NoSolution` in `try_evaluate_added_goals`?
+ //
+ // If so, then it can no longer be used to make a canonical query response,
+ // since subsequent calls to `try_evaluate_added_goals` have possibly dropped
+ // ambiguous goals. Instead, a probe needs to be introduced somewhere in the
+ // evaluation code.
+ tainted: Result<(), NoSolution>,
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
@@ -117,10 +133,16 @@ impl<'tcx> InferCtxtEvalExt<'tcx> for InferCtxt<'tcx> {
let mut ecx = EvalCtxt {
search_graph: &mut search_graph,
infcx: self,
+ // Only relevant when canonicalizing the response,
+ // which we don't do within this evaluation context.
+ predefined_opaques_in_body: self
+ .tcx
+ .mk_predefined_opaques_in_body(PredefinedOpaquesData::default()),
// Only relevant when canonicalizing the response.
max_input_universe: ty::UniverseIndex::ROOT,
var_values: CanonicalVarValues::dummy(),
nested_goals: NestedGoals::new(),
+ tainted: Ok(()),
};
let result = ecx.evaluate_goal(IsNormalizesToHack::No, goal);
@@ -152,28 +174,53 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
fn evaluate_canonical_goal(
tcx: TyCtxt<'tcx>,
search_graph: &'a mut search_graph::SearchGraph<'tcx>,
- canonical_goal: CanonicalGoal<'tcx>,
+ canonical_input: CanonicalInput<'tcx>,
) -> QueryResult<'tcx> {
// Deal with overflow, caching, and coinduction.
//
// The actual solver logic happens in `ecx.compute_goal`.
- search_graph.with_new_goal(tcx, canonical_goal, |search_graph| {
+ search_graph.with_new_goal(tcx, canonical_input, |search_graph| {
let intercrate = match search_graph.solver_mode() {
SolverMode::Normal => false,
SolverMode::Coherence => true,
};
- let (ref infcx, goal, var_values) = tcx
+ let (ref infcx, input, var_values) = tcx
.infer_ctxt()
.intercrate(intercrate)
- .build_with_canonical(DUMMY_SP, &canonical_goal);
+ .with_opaque_type_inference(canonical_input.value.anchor)
+ .build_with_canonical(DUMMY_SP, &canonical_input);
+
+ for &(a, b) in &input.predefined_opaques_in_body.opaque_types {
+ let InferOk { value: (), obligations } = infcx
+ .register_hidden_type_in_new_solver(a, input.goal.param_env, b)
+ .expect("expected opaque type instantiation to succeed");
+ // We're only registering opaques already defined by the caller,
+ // so we're not responsible for proving that they satisfy their
+ // item bounds, unless we use them in a normalizes-to goal,
+ // which is handled in `EvalCtxt::unify_existing_opaque_tys`.
+ let _ = obligations;
+ }
let mut ecx = EvalCtxt {
infcx,
var_values,
- max_input_universe: canonical_goal.max_universe,
+ predefined_opaques_in_body: input.predefined_opaques_in_body,
+ max_input_universe: canonical_input.max_universe,
search_graph,
nested_goals: NestedGoals::new(),
+ tainted: Ok(()),
};
- ecx.compute_goal(goal)
+
+ let result = ecx.compute_goal(input.goal);
+
+ // When creating a query response we clone the opaque type constraints
+ // instead of taking them. This would cause an ICE here, since we have
+ // assertions against dropping an `InferCtxt` without taking opaques.
+ // FIXME: Once we remove support for the old impl we can remove this.
+ if input.anchor != DefiningAnchor::Error {
+ let _ = infcx.take_opaque_types();
+ }
+
+ result
})
}
@@ -188,7 +235,8 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
- let has_changed = !canonical_response.value.var_values.is_identity();
+ let has_changed = !canonical_response.value.var_values.is_identity()
+ || !canonical_response.value.external_constraints.opaque_types.is_empty();
let (certainty, nested_goals) = self.instantiate_and_apply_query_response(
goal.param_env,
orig_values,
@@ -213,18 +261,20 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
{
debug!("rerunning goal to check result is stable");
let (_orig_values, canonical_goal) = self.canonicalize_goal(goal);
- let canonical_response =
+ let new_canonical_response =
EvalCtxt::evaluate_canonical_goal(self.tcx(), self.search_graph, canonical_goal)?;
- if !canonical_response.value.var_values.is_identity() {
+ if !new_canonical_response.value.var_values.is_identity() {
bug!(
"unstable result: re-canonicalized goal={canonical_goal:#?} \
- response={canonical_response:#?}"
+ first_response={canonical_response:#?} \
+ second_response={new_canonical_response:#?}"
);
}
- if certainty != canonical_response.value.certainty {
+ if certainty != new_canonical_response.value.certainty {
bug!(
"unstable certainty: {certainty:#?} re-canonicalized goal={canonical_goal:#?} \
- response={canonical_response:#?}"
+ first_response={canonical_response:#?} \
+ second_response={new_canonical_response:#?}"
);
}
}
@@ -391,6 +441,10 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
},
);
+ if response.is_err() {
+ self.tainted = Err(NoSolution);
+ }
+
self.nested_goals = goals;
response
}
@@ -401,9 +455,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let mut ecx = EvalCtxt {
infcx: self.infcx,
var_values: self.var_values,
+ predefined_opaques_in_body: self.predefined_opaques_in_body,
max_input_universe: self.max_input_universe,
search_graph: self.search_graph,
nested_goals: self.nested_goals.clone(),
+ tainted: self.tainted,
};
self.infcx.probe(|_| f(&mut ecx))
}
@@ -419,6 +475,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
})
}
+ pub(super) fn next_region_infer(&self) -> ty::Region<'tcx> {
+ self.infcx.next_region_var(RegionVariableOrigin::MiscVariable(DUMMY_SP))
+ }
+
pub(super) fn next_const_infer(&self, ty: Ty<'tcx>) -> ty::Const<'tcx> {
self.infcx.next_const_var(
ty,
@@ -649,7 +709,7 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// FIXME(transmutability): This really should be returning nested goals for `Answer::If*`
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
ObligationCause::dummy(),
- ty::Binder::dummy(src_and_dst),
+ src_and_dst,
scope,
assume,
) {
@@ -660,4 +720,56 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
| rustc_transmute::Answer::IfAny(_) => Err(NoSolution),
}
}
+
+ pub(super) fn can_define_opaque_ty(&mut self, def_id: LocalDefId) -> bool {
+ self.infcx.opaque_type_origin(def_id).is_some()
+ }
+
+ pub(super) fn register_opaque_ty(
+ &mut self,
+ a: ty::OpaqueTypeKey<'tcx>,
+ b: Ty<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ) -> Result<(), NoSolution> {
+ let InferOk { value: (), obligations } =
+ self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?;
+ self.add_goals(obligations.into_iter().map(|obligation| obligation.into()));
+ Ok(())
+ }
+
+ // Do something for each opaque/hidden pair defined with `def_id` in the
+ // current inference context.
+ pub(super) fn unify_existing_opaque_tys(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ key: ty::OpaqueTypeKey<'tcx>,
+ ty: Ty<'tcx>,
+ ) -> Vec<CanonicalResponse<'tcx>> {
+ // FIXME: Super inefficient to be cloning this...
+ let opaques = self.infcx.clone_opaque_types_for_query_response();
+
+ let mut values = vec![];
+ for (candidate_key, candidate_ty) in opaques {
+ if candidate_key.def_id != key.def_id {
+ continue;
+ }
+ values.extend(self.probe(|ecx| {
+ for (a, b) in std::iter::zip(candidate_key.substs, key.substs) {
+ ecx.eq(param_env, a, b)?;
+ }
+ ecx.eq(param_env, candidate_ty, ty)?;
+ let mut obl = vec![];
+ ecx.infcx.add_item_bounds_for_hidden_type(
+ candidate_key,
+ ObligationCause::dummy(),
+ param_env,
+ candidate_ty,
+ &mut obl,
+ );
+ ecx.add_goals(obl.into_iter().map(Into::into));
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }));
+ }
+ values
+ }
}
diff --git a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
index ada868705..fdb209fbf 100644
--- a/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
+++ b/compiler/rustc_trait_selection/src/solve/eval_ctxt/canonical.rs
@@ -8,15 +8,19 @@
/// section of the [rustc-dev-guide][c].
///
/// [c]: https://rustc-dev-guide.rust-lang.org/solve/canonicalization.html
-use super::{CanonicalGoal, Certainty, EvalCtxt, Goal};
+use super::{CanonicalInput, Certainty, EvalCtxt, Goal};
use crate::solve::canonicalize::{CanonicalizeMode, Canonicalizer};
use crate::solve::{CanonicalResponse, QueryResult, Response};
+use rustc_index::IndexVec;
use rustc_infer::infer::canonical::query_response::make_query_region_constraints;
use rustc_infer::infer::canonical::CanonicalVarValues;
use rustc_infer::infer::canonical::{CanonicalExt, QueryRegionConstraints};
+use rustc_infer::infer::InferOk;
use rustc_middle::traits::query::NoSolution;
-use rustc_middle::traits::solve::{ExternalConstraints, ExternalConstraintsData};
-use rustc_middle::ty::{self, GenericArgKind};
+use rustc_middle::traits::solve::{
+ ExternalConstraints, ExternalConstraintsData, MaybeCause, PredefinedOpaquesData, QueryInput,
+};
+use rustc_middle::ty::{self, BoundVar, GenericArgKind, Ty};
use rustc_span::DUMMY_SP;
use std::iter;
use std::ops::Deref;
@@ -27,13 +31,21 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
pub(super) fn canonicalize_goal(
&self,
goal: Goal<'tcx, ty::Predicate<'tcx>>,
- ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalGoal<'tcx>) {
+ ) -> (Vec<ty::GenericArg<'tcx>>, CanonicalInput<'tcx>) {
let mut orig_values = Default::default();
let canonical_goal = Canonicalizer::canonicalize(
self.infcx,
CanonicalizeMode::Input,
&mut orig_values,
- goal,
+ QueryInput {
+ goal,
+ anchor: self.infcx.defining_use_anchor,
+ predefined_opaques_in_body: self.tcx().mk_predefined_opaques_in_body(
+ PredefinedOpaquesData {
+ opaque_types: self.infcx.clone_opaque_types_for_query_response(),
+ },
+ ),
+ },
);
(orig_values, canonical_goal)
}
@@ -50,11 +62,36 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
certainty: Certainty,
) -> QueryResult<'tcx> {
let goals_certainty = self.try_evaluate_added_goals()?;
+ assert_eq!(
+ self.tainted,
+ Ok(()),
+ "EvalCtxt is tainted -- nested goals may have been dropped in a \
+ previous call to `try_evaluate_added_goals!`"
+ );
+
let certainty = certainty.unify_with(goals_certainty);
- let external_constraints = self.compute_external_query_constraints()?;
+ let response = match certainty {
+ Certainty::Yes | Certainty::Maybe(MaybeCause::Ambiguity) => {
+ let external_constraints = self.compute_external_query_constraints()?;
+ Response { var_values: self.var_values, external_constraints, certainty }
+ }
+ Certainty::Maybe(MaybeCause::Overflow) => {
+ // If we have overflow, it's probable that we're substituting a type
+ // into itself infinitely and any partial substitutions in the query
+ // response are probably not useful anyways, so just return an empty
+ // query response.
+ //
+ // This may prevent us from potentially useful inference, e.g.
+ // 2 candidates, one ambiguous and one overflow, which both
+ // have the same inference constraints.
+ //
+ // Changing this to retain some constraints in the future
+ // won't be a breaking change, so this is good enough for now.
+ return Ok(self.make_ambiguous_response_no_constraints(MaybeCause::Overflow));
+ }
+ };
- let response = Response { var_values: self.var_values, external_constraints, certainty };
let canonical = Canonicalizer::canonicalize(
self.infcx,
CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
@@ -64,6 +101,40 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Ok(canonical)
}
+ /// Constructs a totally unconstrained, ambiguous response to a goal.
+ ///
+ /// Take care when using this, since often it's useful to respond with
+ /// ambiguity but return constrained variables to guide inference.
+ pub(in crate::solve) fn make_ambiguous_response_no_constraints(
+ &self,
+ maybe_cause: MaybeCause,
+ ) -> CanonicalResponse<'tcx> {
+ let unconstrained_response = Response {
+ var_values: CanonicalVarValues {
+ var_values: self.tcx().mk_substs_from_iter(self.var_values.var_values.iter().map(
+ |arg| -> ty::GenericArg<'tcx> {
+ match arg.unpack() {
+ GenericArgKind::Lifetime(_) => self.next_region_infer().into(),
+ GenericArgKind::Type(_) => self.next_ty_infer().into(),
+ GenericArgKind::Const(ct) => self.next_const_infer(ct.ty()).into(),
+ }
+ },
+ )),
+ },
+ external_constraints: self
+ .tcx()
+ .mk_external_constraints(ExternalConstraintsData::default()),
+ certainty: Certainty::Maybe(maybe_cause),
+ };
+
+ Canonicalizer::canonicalize(
+ self.infcx,
+ CanonicalizeMode::Response { max_input_universe: self.max_input_universe },
+ &mut Default::default(),
+ unconstrained_response,
+ )
+ }
+
#[instrument(level = "debug", skip(self), ret)]
fn compute_external_query_constraints(&self) -> Result<ExternalConstraints<'tcx>, NoSolution> {
// Cannot use `take_registered_region_obligations` as we may compute the response
@@ -78,7 +149,13 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
region_constraints,
)
});
- let opaque_types = self.infcx.clone_opaque_types_for_query_response();
+
+ let mut opaque_types = self.infcx.clone_opaque_types_for_query_response();
+ // Only return opaque type keys for newly-defined opaques
+ opaque_types.retain(|(a, _)| {
+ self.predefined_opaques_in_body.opaque_types.iter().all(|(pa, _)| pa != a)
+ });
+
Ok(self
.tcx()
.mk_external_constraints(ExternalConstraintsData { region_constraints, opaque_types }))
@@ -104,10 +181,10 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let nested_goals = self.unify_query_var_values(param_env, &original_values, var_values)?;
- // FIXME: implement external constraints.
- let ExternalConstraintsData { region_constraints, opaque_types: _ } =
+ let ExternalConstraintsData { region_constraints, opaque_types } =
external_constraints.deref();
self.register_region_constraints(region_constraints);
+ self.register_opaque_types(param_env, opaque_types)?;
Ok((certainty, nested_goals))
}
@@ -139,25 +216,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
//
// We therefore instantiate the existential variable in the canonical response with the
// inference variable of the input right away, which is more performant.
- let mut opt_values = vec![None; response.variables.len()];
+ let mut opt_values = IndexVec::from_elem_n(None, response.variables.len());
for (original_value, result_value) in iter::zip(original_values, var_values.var_values) {
match result_value.unpack() {
GenericArgKind::Type(t) => {
if let &ty::Bound(debruijn, b) = t.kind() {
assert_eq!(debruijn, ty::INNERMOST);
- opt_values[b.var.index()] = Some(*original_value);
+ opt_values[b.var] = Some(*original_value);
}
}
GenericArgKind::Lifetime(r) => {
if let ty::ReLateBound(debruijn, br) = *r {
assert_eq!(debruijn, ty::INNERMOST);
- opt_values[br.var.index()] = Some(*original_value);
+ opt_values[br.var] = Some(*original_value);
}
}
GenericArgKind::Const(c) => {
- if let ty::ConstKind::Bound(debrujin, b) = c.kind() {
- assert_eq!(debrujin, ty::INNERMOST);
- opt_values[b.index()] = Some(*original_value);
+ if let ty::ConstKind::Bound(debruijn, b) = c.kind() {
+ assert_eq!(debruijn, ty::INNERMOST);
+ opt_values[b] = Some(*original_value);
}
}
}
@@ -176,11 +253,11 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// As an optimization we sometimes avoid creating a new inference variable here.
//
// All new inference variables we create start out in the current universe of the caller.
- // This is conceptionally wrong as these inference variables would be able to name
+ // This is conceptually wrong as these inference variables would be able to name
// more placeholders then they should be able to. However the inference variables have
// to "come from somewhere", so by equating them with the original values of the caller
// later on, we pull them down into their correct universe again.
- if let Some(v) = opt_values[index] {
+ if let Some(v) = opt_values[BoundVar::from_usize(index)] {
v
} else {
self.infcx.instantiate_canonical_var(DUMMY_SP, info, |_| prev_universe)
@@ -227,4 +304,19 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
let _ = member_constraint;
}
}
+
+ fn register_opaque_types(
+ &mut self,
+ param_env: ty::ParamEnv<'tcx>,
+ opaque_types: &[(ty::OpaqueTypeKey<'tcx>, Ty<'tcx>)],
+ ) -> Result<(), NoSolution> {
+ for &(a, b) in opaque_types {
+ let InferOk { value: (), obligations } =
+ self.infcx.register_hidden_type_in_new_solver(a, param_env, b)?;
+ // It's sound to drop these obligations, since the normalizes-to goal
+ // is responsible for proving these obligations.
+ let _ = obligations;
+ }
+ Ok(())
+ }
}
diff --git a/compiler/rustc_trait_selection/src/solve/fulfill.rs b/compiler/rustc_trait_selection/src/solve/fulfill.rs
index 32bd10f0b..4a403196c 100644
--- a/compiler/rustc_trait_selection/src/solve/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/solve/fulfill.rs
@@ -133,12 +133,14 @@ impl<'tcx> TraitEngine<'tcx> for FulfillmentCtxt<'tcx> {
| ty::PredicateKind::ObjectSafe(_)
| ty::PredicateKind::ClosureKind(_, _, _)
| ty::PredicateKind::ConstEvaluatable(_)
- | ty::PredicateKind::TypeWellFormedFromEnv(_)
| ty::PredicateKind::Ambiguous => {
FulfillmentErrorCode::CodeSelectionError(
SelectionError::Unimplemented,
)
}
+ ty::PredicateKind::TypeWellFormedFromEnv(_) => {
+ bug!("unexpected goal: {goal:?}")
+ }
},
root_obligation: obligation,
});
diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs
index 19bcbd461..56a254d9c 100644
--- a/compiler/rustc_trait_selection/src/solve/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/mod.rs
@@ -24,6 +24,7 @@ mod assembly;
mod canonicalize;
mod eval_ctxt;
mod fulfill;
+mod opaques;
mod project_goals;
mod search_graph;
mod trait_goals;
@@ -212,7 +213,7 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
);
}
- match (lhs.to_projection_term(tcx), rhs.to_projection_term(tcx)) {
+ match (lhs.to_alias_ty(tcx), rhs.to_alias_ty(tcx)) {
(None, None) => bug!("`AliasRelate` goal without an alias on either lhs or rhs"),
// RHS is not a projection, only way this is true is if LHS normalizes-to RHS
@@ -230,44 +231,60 @@ impl<'a, 'tcx> EvalCtxt<'a, 'tcx> {
let mut candidates = Vec::new();
// LHS normalizes-to RHS
- candidates.extend(
- evaluate_normalizes_to(self, alias_lhs, rhs, direction, Invert::No).ok(),
- );
+ candidates.extend(evaluate_normalizes_to(
+ self,
+ alias_lhs,
+ rhs,
+ direction,
+ Invert::No,
+ ));
// RHS normalizes-to RHS
- candidates.extend(
- evaluate_normalizes_to(self, alias_rhs, lhs, direction, Invert::Yes).ok(),
- );
+ candidates.extend(evaluate_normalizes_to(
+ self,
+ alias_rhs,
+ lhs,
+ direction,
+ Invert::Yes,
+ ));
// Relate via substs
- candidates.extend(
- self.probe(|ecx| {
- let span = tracing::span!(
- tracing::Level::DEBUG,
- "compute_alias_relate_goal(relate_via_substs)",
- ?alias_lhs,
- ?alias_rhs,
- ?direction
- );
- let _enter = span.enter();
-
- match direction {
- ty::AliasRelationDirection::Equate => {
- ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
- }
- ty::AliasRelationDirection::Subtype => {
- ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
- }
+ let subst_relate_response = self.probe(|ecx| {
+ let span = tracing::span!(
+ tracing::Level::DEBUG,
+ "compute_alias_relate_goal(relate_via_substs)",
+ ?alias_lhs,
+ ?alias_rhs,
+ ?direction
+ );
+ let _enter = span.enter();
+
+ match direction {
+ ty::AliasRelationDirection::Equate => {
+ ecx.eq(goal.param_env, alias_lhs, alias_rhs)?;
+ }
+ ty::AliasRelationDirection::Subtype => {
+ ecx.sub(goal.param_env, alias_lhs, alias_rhs)?;
}
+ }
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- .ok(),
- );
+ ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ });
+ candidates.extend(subst_relate_response);
debug!(?candidates);
if let Some(merged) = self.try_merge_responses(&candidates) {
Ok(merged)
} else {
- self.flounder(&candidates)
+ // When relating two aliases and we have ambiguity, we prefer
+ // relating the generic arguments of the aliases over normalizing
+ // them. This is necessary for inference during typeck.
+ //
+ // As this is incomplete, we must not do so during coherence.
+ match (self.solver_mode(), subst_relate_response) {
+ (SolverMode::Normal, Ok(response)) => Ok(response),
+ (SolverMode::Normal, Err(NoSolution)) | (SolverMode::Coherence, _) => {
+ self.flounder(&candidates)
+ }
+ }
}
}
}
@@ -340,17 +357,17 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
if responses.is_empty() {
return Err(NoSolution);
}
- let certainty = responses.iter().fold(Certainty::AMBIGUOUS, |certainty, response| {
- certainty.unify_with(response.value.certainty)
- });
-
- let response = self.evaluate_added_goals_and_make_canonical_response(certainty);
- if let Ok(response) = response {
- assert!(response.has_no_inference_or_external_constraints());
- Ok(response)
- } else {
- bug!("failed to make floundered response: {responses:?}");
- }
+
+ let Certainty::Maybe(maybe_cause) = responses.iter().fold(
+ Certainty::AMBIGUOUS,
+ |certainty, response| {
+ certainty.unify_with(response.value.certainty)
+ },
+ ) else {
+ bug!("expected flounder response to be ambiguous")
+ };
+
+ Ok(self.make_ambiguous_response_no_constraints(maybe_cause))
}
}
diff --git a/compiler/rustc_trait_selection/src/solve/opaques.rs b/compiler/rustc_trait_selection/src/solve/opaques.rs
new file mode 100644
index 000000000..a5de4ddee
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/solve/opaques.rs
@@ -0,0 +1,67 @@
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::solve::{Certainty, Goal, QueryResult};
+use rustc_middle::traits::Reveal;
+use rustc_middle::ty;
+use rustc_middle::ty::util::NotUniqueParam;
+
+use super::{EvalCtxt, SolverMode};
+
+impl<'tcx> EvalCtxt<'_, 'tcx> {
+ pub(super) fn normalize_opaque_type(
+ &mut self,
+ goal: Goal<'tcx, ty::ProjectionPredicate<'tcx>>,
+ ) -> QueryResult<'tcx> {
+ let tcx = self.tcx();
+ let opaque_ty = goal.predicate.projection_ty;
+ let expected = goal.predicate.term.ty().expect("no such thing as an opaque const");
+
+ match (goal.param_env.reveal(), self.solver_mode()) {
+ (Reveal::UserFacing, SolverMode::Normal) => {
+ let Some(opaque_ty_def_id) = opaque_ty.def_id.as_local() else {
+ return Err(NoSolution);
+ };
+ let opaque_ty =
+ ty::OpaqueTypeKey { def_id: opaque_ty_def_id, substs: opaque_ty.substs };
+ // FIXME: at some point we should call queries without defining
+ // new opaque types but having the existing opaque type definitions.
+ // This will require moving this below "Prefer opaques registered already".
+ if !self.can_define_opaque_ty(opaque_ty_def_id) {
+ return Err(NoSolution);
+ }
+ // FIXME: This may have issues when the substs contain aliases...
+ match self.tcx().uses_unique_placeholders_ignoring_regions(opaque_ty.substs) {
+ Err(NotUniqueParam::NotParam(param)) if param.is_non_region_infer() => {
+ return self.evaluate_added_goals_and_make_canonical_response(
+ Certainty::AMBIGUOUS,
+ );
+ }
+ Err(_) => {
+ return Err(NoSolution);
+ }
+ Ok(()) => {}
+ }
+ // Prefer opaques registered already.
+ let matches = self.unify_existing_opaque_tys(goal.param_env, opaque_ty, expected);
+ if !matches.is_empty() {
+ if let Some(response) = self.try_merge_responses(&matches) {
+ return Ok(response);
+ } else {
+ return self.flounder(&matches);
+ }
+ }
+ // Otherwise, define a new opaque type
+ self.register_opaque_ty(opaque_ty, expected, goal.param_env)?;
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ (Reveal::UserFacing, SolverMode::Coherence) => {
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS)
+ }
+ (Reveal::All, _) => {
+ // FIXME: Add an assertion that opaque type storage is empty.
+ let actual = tcx.type_of(opaque_ty.def_id).subst(tcx, opaque_ty.substs);
+ self.eq(goal.param_env, expected, actual)?;
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/solve/project_goals.rs b/compiler/rustc_trait_selection/src/solve/project_goals.rs
index 14cb43b89..7d7dfa2c8 100644
--- a/compiler/rustc_trait_selection/src/solve/project_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/project_goals.rs
@@ -22,19 +22,25 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
&mut self,
goal: Goal<'tcx, ProjectionPredicate<'tcx>>,
) -> QueryResult<'tcx> {
- // To only compute normalization once for each projection we only
- // normalize if the expected term is an unconstrained inference variable.
- //
- // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
- // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
- // `U` and equate it with `u32`. This means that we don't need a separate
- // projection cache in the solver.
- if self.term_is_fully_unconstrained(goal) {
- let candidates = self.assemble_and_evaluate_candidates(goal);
- self.merge_candidates(candidates)
- } else {
- self.set_normalizes_to_hack_goal(goal);
- self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ match goal.predicate.projection_ty.kind(self.tcx()) {
+ ty::AliasKind::Projection => {
+ // To only compute normalization once for each projection we only
+ // normalize if the expected term is an unconstrained inference variable.
+ //
+ // E.g. for `<T as Trait>::Assoc == u32` we recursively compute the goal
+ // `exists<U> <T as Trait>::Assoc == U` and then take the resulting type for
+ // `U` and equate it with `u32`. This means that we don't need a separate
+ // projection cache in the solver.
+ if self.term_is_fully_unconstrained(goal) {
+ let candidates = self.assemble_and_evaluate_candidates(goal);
+ self.merge_candidates(candidates)
+ } else {
+ self.set_normalizes_to_hack_goal(goal);
+ self.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ }
+ }
+ ty::AliasKind::Opaque => self.normalize_opaque_type(goal),
+ ty::AliasKind::Inherent => bug!("IATs not supported here yet"),
}
}
}
@@ -56,11 +62,11 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
self.trait_def_id(tcx)
}
- fn consider_implied_clause(
+ fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
&& poly_projection_pred.projection_def_id() == goal.predicate.def_id()
@@ -73,49 +79,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
goal.predicate.projection_ty,
assumption_projection_pred.projection_ty,
)?;
- ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
- ecx.add_goals(requirements);
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- } else {
- Err(NoSolution)
- }
- }
-
- fn consider_object_bound_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- assumption: ty::Predicate<'tcx>,
- ) -> QueryResult<'tcx> {
- if let Some(poly_projection_pred) = assumption.to_opt_poly_projection_pred()
- && poly_projection_pred.projection_def_id() == goal.predicate.def_id()
- {
- ecx.probe(|ecx| {
- let tcx = ecx.tcx();
-
- let assumption_projection_pred =
- ecx.instantiate_binder_with_infer(poly_projection_pred);
- ecx.eq(
- goal.param_env,
- goal.predicate.projection_ty,
- assumption_projection_pred.projection_ty,
- )?;
-
- let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
- bug!("expected object type in `consider_object_bound_candidate`");
- };
- ecx.add_goals(
- structural_traits::predicates_for_object_candidate(
- &ecx,
- goal.param_env,
- goal.predicate.projection_ty.trait_ref(tcx),
- bounds,
- )
- .into_iter()
- .map(|pred| goal.with(tcx, pred)),
- );
- ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)?;
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ ecx.eq(goal.param_env, goal.predicate.term, assumption_projection_pred.term)
+ .expect("expected goal term to be fully unconstrained");
+ then(ecx)
})
} else {
Err(NoSolution)
@@ -164,10 +130,24 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
};
if !assoc_def.item.defaultness(tcx).has_value() {
- tcx.sess.delay_span_bug(
+ let guar = tcx.sess.delay_span_bug(
tcx.def_span(assoc_def.item.def_id),
"missing value for assoc item in impl",
);
+ let error_term = match assoc_def.item.kind {
+ ty::AssocKind::Const => tcx
+ .const_error(
+ tcx.type_of(goal.predicate.def_id())
+ .subst(tcx, goal.predicate.projection_ty.substs),
+ guar,
+ )
+ .into(),
+ ty::AssocKind::Type => tcx.ty_error(guar).into(),
+ ty::AssocKind::Fn => unreachable!(),
+ };
+ ecx.eq(goal.param_env, goal.predicate.term, error_term)
+ .expect("expected goal term to be fully unconstrained");
+ return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes);
}
// Getting the right substitutions here is complex, e.g. given:
@@ -198,7 +178,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
let identity_substs =
ty::InternalSubsts::identity_for_item(tcx, assoc_def.item.def_id);
- let did = ty::WithOptConstParam::unknown(assoc_def.item.def_id);
+ let did = assoc_def.item.def_id;
let kind =
ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
@@ -206,7 +186,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ty.map_bound(|ty| ty.into())
};
- ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))?;
+ ecx.eq(goal.param_env, goal.predicate.term, term.subst(tcx, substs))
+ .expect("expected goal term to be fully unconstrained");
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -271,8 +252,9 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
}
};
- let output_is_sized_pred = tupled_inputs_and_output
- .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
+ let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
+ ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+ });
let pred = tupled_inputs_and_output
.map_bound(|(inputs, output)| ty::ProjectionPredicate {
@@ -330,10 +312,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
ty::Alias(_, _) | ty::Param(_) | ty::Placeholder(..) => {
// FIXME(ptr_metadata): It would also be possible to return a `Ok(Ambig)` with no constraints.
- let sized_predicate = ty::Binder::dummy(tcx.at(DUMMY_SP).mk_trait_ref(
+ let sized_predicate = ty::TraitRef::from_lang_item(
+ tcx,
LangItem::Sized,
+ DUMMY_SP,
[ty::GenericArg::from(goal.predicate.self_ty())],
- ));
+ );
ecx.add_goal(goal.with(tcx, sized_predicate));
tcx.types.unit
}
@@ -375,7 +359,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
),
};
- ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())?;
+ ecx.eq(goal.param_env, goal.predicate.term, metadata_ty.into())
+ .expect("expected goal term to be fully unconstrained");
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
@@ -513,7 +498,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> {
};
ecx.probe(|ecx| {
- ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())?;
+ ecx.eq(goal.param_env, goal.predicate.term, discriminant_ty.into())
+ .expect("expected goal term to be fully unconstrained");
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
})
}
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
index d1b4fa554..56f126e91 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/cache.rs
@@ -10,8 +10,8 @@
//! before then or if I still haven't done that before January 2023.
use super::StackDepth;
use rustc_data_structures::fx::FxHashMap;
-use rustc_index::vec::IndexVec;
-use rustc_middle::traits::solve::{CanonicalGoal, QueryResult};
+use rustc_index::IndexVec;
+use rustc_middle::traits::solve::{CanonicalInput, QueryResult};
rustc_index::newtype_index! {
pub struct EntryIndex {}
@@ -34,7 +34,7 @@ pub(super) struct ProvisionalEntry<'tcx> {
// The goal for this entry. Should always be equal to the corresponding goal
// in the lookup table.
- pub(super) goal: CanonicalGoal<'tcx>,
+ pub(super) input: CanonicalInput<'tcx>,
}
pub(super) struct ProvisionalCache<'tcx> {
@@ -42,7 +42,7 @@ pub(super) struct ProvisionalCache<'tcx> {
// FIXME: This is only used to quickly check whether a given goal
// is in the cache. We should experiment with using something like
// `SsoHashSet` here because in most cases there are only a few entries.
- pub(super) lookup_table: FxHashMap<CanonicalGoal<'tcx>, EntryIndex>,
+ pub(super) lookup_table: FxHashMap<CanonicalInput<'tcx>, EntryIndex>,
}
impl<'tcx> ProvisionalCache<'tcx> {
diff --git a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
index 050269fa9..19e4b2300 100644
--- a/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
+++ b/compiler/rustc_trait_selection/src/solve/search_graph/mod.rs
@@ -6,9 +6,9 @@ pub(super) use overflow::OverflowHandler;
use self::cache::ProvisionalEntry;
use cache::ProvisionalCache;
use overflow::OverflowData;
-use rustc_index::vec::IndexVec;
+use rustc_index::IndexVec;
use rustc_middle::dep_graph::DepKind;
-use rustc_middle::traits::solve::{CanonicalGoal, Certainty, MaybeCause, QueryResult};
+use rustc_middle::traits::solve::{CanonicalInput, Certainty, MaybeCause, QueryResult};
use rustc_middle::ty::TyCtxt;
use std::{collections::hash_map::Entry, mem};
@@ -19,7 +19,7 @@ rustc_index::newtype_index! {
}
struct StackElem<'tcx> {
- goal: CanonicalGoal<'tcx>,
+ input: CanonicalInput<'tcx>,
has_been_used: bool,
}
@@ -77,7 +77,7 @@ impl<'tcx> SearchGraph<'tcx> {
}
// ...or it depends on a goal with a lower depth.
- let current_goal = self.stack[stack_depth].goal;
+ let current_goal = self.stack[stack_depth].input;
let entry_index = self.provisional_cache.lookup_table[&current_goal];
self.provisional_cache.entries[entry_index].depth != stack_depth
} else {
@@ -92,20 +92,20 @@ impl<'tcx> SearchGraph<'tcx> {
fn try_push_stack(
&mut self,
tcx: TyCtxt<'tcx>,
- goal: CanonicalGoal<'tcx>,
+ input: CanonicalInput<'tcx>,
) -> Result<(), QueryResult<'tcx>> {
// Look at the provisional cache to check for cycles.
let cache = &mut self.provisional_cache;
- match cache.lookup_table.entry(goal) {
+ match cache.lookup_table.entry(input) {
// No entry, simply push this goal on the stack after dealing with overflow.
Entry::Vacant(v) => {
if self.overflow_data.has_overflow(self.stack.len()) {
- return Err(self.deal_with_overflow(tcx, goal));
+ return Err(self.deal_with_overflow(tcx, input));
}
- let depth = self.stack.push(StackElem { goal, has_been_used: false });
- let response = super::response_no_constraints(tcx, goal, Certainty::Yes);
- let entry_index = cache.entries.push(ProvisionalEntry { response, depth, goal });
+ let depth = self.stack.push(StackElem { input, has_been_used: false });
+ let response = super::response_no_constraints(tcx, input, Certainty::Yes);
+ let entry_index = cache.entries.push(ProvisionalEntry { response, depth, input });
v.insert(entry_index);
Ok(())
}
@@ -135,13 +135,13 @@ impl<'tcx> SearchGraph<'tcx> {
// the stack is enough.
if self.stack.raw[stack_depth.index()..]
.iter()
- .all(|g| g.goal.value.predicate.is_coinductive(tcx))
+ .all(|g| g.input.value.goal.predicate.is_coinductive(tcx))
{
Err(cache.provisional_result(entry_index))
} else {
Err(super::response_no_constraints(
tcx,
- goal,
+ input,
Certainty::Maybe(MaybeCause::Overflow),
))
}
@@ -161,18 +161,18 @@ impl<'tcx> SearchGraph<'tcx> {
/// updated the provisional cache and we have to recompute the current goal.
///
/// FIXME: Refer to the rustc-dev-guide entry once it exists.
- #[instrument(level = "debug", skip(self, actual_goal), ret)]
+ #[instrument(level = "debug", skip(self, actual_input), ret)]
fn try_finalize_goal(
&mut self,
- actual_goal: CanonicalGoal<'tcx>,
+ actual_input: CanonicalInput<'tcx>,
response: QueryResult<'tcx>,
) -> bool {
let stack_elem = self.stack.pop().unwrap();
- let StackElem { goal, has_been_used } = stack_elem;
- assert_eq!(goal, actual_goal);
+ let StackElem { input, has_been_used } = stack_elem;
+ assert_eq!(input, actual_input);
let cache = &mut self.provisional_cache;
- let provisional_entry_index = *cache.lookup_table.get(&goal).unwrap();
+ let provisional_entry_index = *cache.lookup_table.get(&input).unwrap();
let provisional_entry = &mut cache.entries[provisional_entry_index];
// We eagerly update the response in the cache here. If we have to reevaluate
// this goal we use the new response when hitting a cycle, and we definitely
@@ -194,7 +194,7 @@ impl<'tcx> SearchGraph<'tcx> {
cache.entries.truncate(provisional_entry_index.index() + 1);
// ...and finally push our goal back on the stack and reevaluate it.
- self.stack.push(StackElem { goal, has_been_used: false });
+ self.stack.push(StackElem { input, has_been_used: false });
false
} else {
true
@@ -204,17 +204,17 @@ impl<'tcx> SearchGraph<'tcx> {
pub(super) fn with_new_goal(
&mut self,
tcx: TyCtxt<'tcx>,
- canonical_goal: CanonicalGoal<'tcx>,
+ canonical_input: CanonicalInput<'tcx>,
mut loop_body: impl FnMut(&mut Self) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if self.should_use_global_cache() {
- if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_goal, tcx) {
- debug!(?canonical_goal, ?result, "cache hit");
+ if let Some(result) = tcx.new_solver_evaluation_cache.get(&canonical_input, tcx) {
+ debug!(?canonical_input, ?result, "cache hit");
return result;
}
}
- match self.try_push_stack(tcx, canonical_goal) {
+ match self.try_push_stack(tcx, canonical_input) {
Ok(()) => {}
// Our goal is already on the stack, eager return.
Err(response) => return response,
@@ -226,19 +226,19 @@ impl<'tcx> SearchGraph<'tcx> {
let (result, dep_node) = tcx.dep_graph.with_anon_task(tcx, DepKind::TraitSelect, || {
self.repeat_while_none(
|this| {
- let result = this.deal_with_overflow(tcx, canonical_goal);
+ let result = this.deal_with_overflow(tcx, canonical_input);
let _ = this.stack.pop().unwrap();
result
},
|this| {
let result = loop_body(this);
- this.try_finalize_goal(canonical_goal, result).then(|| result)
+ this.try_finalize_goal(canonical_input, result).then(|| result)
},
)
});
let cache = &mut self.provisional_cache;
- let provisional_entry_index = *cache.lookup_table.get(&canonical_goal).unwrap();
+ let provisional_entry_index = *cache.lookup_table.get(&canonical_input).unwrap();
let provisional_entry = &mut cache.entries[provisional_entry_index];
let depth = provisional_entry.depth;
@@ -254,13 +254,13 @@ impl<'tcx> SearchGraph<'tcx> {
// cycle participants without moving them to the global cache.
let other_cycle_participants = provisional_entry_index.index() + 1;
for (i, entry) in cache.entries.drain_enumerated(other_cycle_participants..) {
- let actual_index = cache.lookup_table.remove(&entry.goal);
+ let actual_index = cache.lookup_table.remove(&entry.input);
debug_assert_eq!(Some(i), actual_index);
debug_assert!(entry.depth == depth);
}
let current_goal = cache.entries.pop().unwrap();
- let actual_index = cache.lookup_table.remove(&current_goal.goal);
+ let actual_index = cache.lookup_table.remove(&current_goal.input);
debug_assert_eq!(Some(provisional_entry_index), actual_index);
debug_assert!(current_goal.depth == depth);
@@ -274,7 +274,7 @@ impl<'tcx> SearchGraph<'tcx> {
let can_cache = !self.overflow_data.did_overflow() || self.stack.is_empty();
if self.should_use_global_cache() && can_cache {
tcx.new_solver_evaluation_cache.insert(
- current_goal.goal,
+ current_goal.input,
dep_node,
current_goal.response,
);
diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
index abd11a15a..f722f2813 100644
--- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs
+++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs
@@ -78,16 +78,17 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
})
}
- fn consider_implied_clause(
+ fn probe_and_match_goal_against_assumption(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
assumption: ty::Predicate<'tcx>,
- requirements: impl IntoIterator<Item = Goal<'tcx, ty::Predicate<'tcx>>>,
+ then: impl FnOnce(&mut EvalCtxt<'_, 'tcx>) -> QueryResult<'tcx>,
) -> QueryResult<'tcx> {
if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
&& poly_trait_pred.def_id() == goal.predicate.def_id()
+ && poly_trait_pred.polarity() == goal.predicate.polarity
{
- // FIXME: Constness and polarity
+ // FIXME: Constness
ecx.probe(|ecx| {
let assumption_trait_pred =
ecx.instantiate_binder_with_infer(poly_trait_pred);
@@ -96,57 +97,21 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
goal.predicate.trait_ref,
assumption_trait_pred.trait_ref,
)?;
- ecx.add_goals(requirements);
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
+ then(ecx)
})
} else {
Err(NoSolution)
}
}
- fn consider_object_bound_candidate(
+ fn consider_auto_trait_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
- assumption: ty::Predicate<'tcx>,
) -> QueryResult<'tcx> {
- if let Some(poly_trait_pred) = assumption.to_opt_poly_trait_pred()
- && poly_trait_pred.def_id() == goal.predicate.def_id()
- {
- // FIXME: Constness and polarity
- ecx.probe(|ecx| {
- let assumption_trait_pred =
- ecx.instantiate_binder_with_infer(poly_trait_pred);
- ecx.eq(
- goal.param_env,
- goal.predicate.trait_ref,
- assumption_trait_pred.trait_ref,
- )?;
-
- let tcx = ecx.tcx();
- let ty::Dynamic(bounds, _, _) = *goal.predicate.self_ty().kind() else {
- bug!("expected object type in `consider_object_bound_candidate`");
- };
- ecx.add_goals(
- structural_traits::predicates_for_object_candidate(
- &ecx,
- goal.param_env,
- goal.predicate.trait_ref,
- bounds,
- )
- .into_iter()
- .map(|pred| goal.with(tcx, pred)),
- );
- ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
- })
- } else {
- Err(NoSolution)
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
}
- }
- fn consider_auto_trait_candidate(
- ecx: &mut EvalCtxt<'_, 'tcx>,
- goal: Goal<'tcx, Self>,
- ) -> QueryResult<'tcx> {
if let Some(result) = ecx.disqualify_auto_trait_candidate_due_to_possible_impl(goal) {
return result;
}
@@ -161,6 +126,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
let tcx = ecx.tcx();
ecx.probe(|ecx| {
@@ -176,6 +145,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
ecx.probe_and_evaluate_goal_for_constituent_tys(
goal,
structural_traits::instantiate_constituent_tys_for_sized_trait,
@@ -186,6 +159,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
ecx.probe_and_evaluate_goal_for_constituent_tys(
goal,
structural_traits::instantiate_constituent_tys_for_copy_clone_trait,
@@ -196,14 +173,22 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
- if goal.predicate.self_ty().has_non_region_infer() {
- return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
}
+ // The regions of a type don't affect the size of the type
let tcx = ecx.tcx();
- let self_ty = tcx.erase_regions(goal.predicate.self_ty());
+ // We should erase regions from both the param-env and type, since both
+ // may have infer regions. Specifically, after canonicalizing and instantiating,
+ // early bound regions turn into region vars in both the new and old solver.
+ let key = tcx.erase_regions(goal.param_env.and(goal.predicate.self_ty()));
+ // But if there are inference variables, we have to wait until it's resolved.
+ if key.has_non_region_infer() {
+ return ecx.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
+ }
- if let Ok(layout) = tcx.layout_of(goal.param_env.and(self_ty))
+ if let Ok(layout) = tcx.layout_of(key)
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
// FIXME: We could make this faster by making a no-constraints response
@@ -217,6 +202,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
if let ty::FnPtr(..) = goal.predicate.self_ty().kind() {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
@@ -229,6 +218,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
goal: Goal<'tcx, Self>,
goal_kind: ty::ClosureKind,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
let tcx = ecx.tcx();
let tupled_inputs_and_output =
match structural_traits::extract_tupled_inputs_and_output_from_callable(
@@ -242,12 +235,13 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS);
}
};
- let output_is_sized_pred = tupled_inputs_and_output
- .map_bound(|(_, output)| tcx.at(DUMMY_SP).mk_trait_ref(LangItem::Sized, [output]));
+ let output_is_sized_pred = tupled_inputs_and_output.map_bound(|(_, output)| {
+ ty::TraitRef::from_lang_item(tcx, LangItem::Sized, DUMMY_SP, [output])
+ });
let pred = tupled_inputs_and_output
.map_bound(|(inputs, _)| {
- tcx.mk_trait_ref(goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
+ ty::TraitRef::new(tcx, goal.predicate.def_id(), [goal.predicate.self_ty(), inputs])
})
.to_predicate(tcx);
// A built-in `Fn` impl only holds if the output is sized.
@@ -259,6 +253,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
if let ty::Tuple(..) = goal.predicate.self_ty().kind() {
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
} else {
@@ -268,8 +266,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
fn consider_builtin_pointee_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
- _goal: Goal<'tcx, Self>,
+ goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -277,6 +279,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
let ty::Generator(def_id, _, _) = *goal.predicate.self_ty().kind() else {
return Err(NoSolution);
};
@@ -297,6 +303,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
let self_ty = goal.predicate.self_ty();
let ty::Generator(def_id, substs, _) = *self_ty.kind() else {
return Err(NoSolution);
@@ -312,10 +322,8 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
Self::consider_implied_clause(
ecx,
goal,
- ty::Binder::dummy(
- tcx.mk_trait_ref(goal.predicate.def_id(), [self_ty, generator.resume_ty()]),
- )
- .to_predicate(tcx),
+ ty::TraitRef::new(tcx, goal.predicate.def_id(), [self_ty, generator.resume_ty()])
+ .to_predicate(tcx),
// Technically, we need to check that the generator types are Sized,
// but that's already proven by the generator being WF.
[],
@@ -326,6 +334,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
let tcx = ecx.tcx();
let a_ty = goal.predicate.self_ty();
let b_ty = goal.predicate.trait_ref.substs.type_at(1);
@@ -346,7 +358,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// Can only unsize to an object-safe type
if data
.principal_def_id()
- .map_or(false, |def_id| !tcx.check_is_object_safe(def_id))
+ .is_some_and(|def_id| !tcx.check_is_object_safe(def_id))
{
return Err(NoSolution);
}
@@ -360,9 +372,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
data.iter().map(|pred| goal.with(tcx, pred.with_self_ty(tcx, a_ty))),
);
// The type must be Sized to be unsized.
- ecx.add_goal(
- goal.with(tcx, ty::Binder::dummy(tcx.mk_trait_ref(sized_def_id, [a_ty]))),
- );
+ ecx.add_goal(goal.with(tcx, ty::TraitRef::new(tcx, sized_def_id, [a_ty])));
// The type must outlive the lifetime of the `dyn` we're unsizing into.
ecx.add_goal(
goal.with(tcx, ty::Binder::dummy(ty::OutlivesPredicate(a_ty, region))),
@@ -411,9 +421,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx.eq(goal.param_env, unsized_a_ty, b_ty)?;
ecx.add_goal(goal.with(
tcx,
- ty::Binder::dummy(
- tcx.mk_trait_ref(goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
- ),
+ ty::TraitRef::new(tcx, goal.predicate.def_id(), [a_tail_ty, b_tail_ty]),
));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -432,9 +440,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
// Similar to ADTs, require that the rest of the fields are equal.
ecx.add_goal(goal.with(
tcx,
- ty::Binder::dummy(
- tcx.mk_trait_ref(goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
- ),
+ ty::TraitRef::new(tcx, goal.predicate.def_id(), [*a_last_ty, *b_last_ty]),
));
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -447,6 +453,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> Vec<CanonicalResponse<'tcx>> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return vec![];
+ }
+
let tcx = ecx.tcx();
let a_ty = goal.predicate.self_ty();
@@ -521,8 +531,12 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
fn consider_builtin_discriminant_kind_candidate(
ecx: &mut EvalCtxt<'_, 'tcx>,
- _goal: Goal<'tcx, Self>,
+ goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
// `DiscriminantKind` is automatically implemented for every type.
ecx.evaluate_added_goals_and_make_canonical_response(Certainty::Yes)
}
@@ -531,6 +545,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
if !goal.param_env.is_const() {
// `Destruct` is automatically implemented for every type in
// non-const environments.
@@ -545,6 +563,10 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> {
ecx: &mut EvalCtxt<'_, 'tcx>,
goal: Goal<'tcx, Self>,
) -> QueryResult<'tcx> {
+ if goal.predicate.polarity != ty::ImplPolarity::Positive {
+ return Err(NoSolution);
+ }
+
// `rustc_transmute` does not have support for type or const params
if goal.has_non_region_placeholders() {
return Err(NoSolution);
@@ -591,12 +613,12 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
Some(self.evaluate_added_goals_and_make_canonical_response(Certainty::AMBIGUOUS))
}
- // These types cannot be structurally decomposed into constitutent
+ // These types cannot be structurally decomposed into constituent
// types, and therefore have no built-in auto impl.
ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..) => Some(Err(NoSolution)),
ty::Infer(_) | ty::Bound(_, _) => bug!("unexpected type `{self_ty}`"),
@@ -645,12 +667,16 @@ impl<'tcx> EvalCtxt<'_, 'tcx> {
// FIXME: Handling opaques here is kinda sus. Especially because we
// simplify them to PlaceholderSimplifiedType.
| ty::Alias(ty::Opaque, _) => {
- if let Some(def_id) = self.tcx().find_map_relevant_impl(
+ let mut disqualifying_impl = None;
+ self.tcx().for_each_relevant_impl_treating_projections(
goal.predicate.def_id(),
goal.predicate.self_ty(),
TreatProjections::NextSolverLookup,
- Some,
- ) {
+ |impl_def_id| {
+ disqualifying_impl = Some(impl_def_id);
+ },
+ );
+ if let Some(def_id) = disqualifying_impl {
debug!(?def_id, ?goal, "disqualified auto-trait implementation");
// No need to actually consider the candidate here,
// since we do that in `consider_impl_candidate`.
diff --git a/compiler/rustc_trait_selection/src/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
index 182d995c4..62d2aad52 100644
--- a/compiler/rustc_trait_selection/src/traits/auto_trait.rs
+++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs
@@ -86,7 +86,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
) -> AutoTraitResult<A> {
let tcx = self.tcx;
- let trait_ref = tcx.mk_trait_ref(trait_did, [ty]);
+ let trait_ref = ty::TraitRef::new(tcx, trait_did, [ty]);
let infcx = tcx.infer_ctxt().build();
let mut selcx = SelectionContext::new(&infcx);
@@ -263,7 +263,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
let mut already_visited = FxHashSet::default();
let mut predicates = VecDeque::new();
predicates.push_back(ty::Binder::dummy(ty::TraitPredicate {
- trait_ref: infcx.tcx.mk_trait_ref(trait_did, [ty]),
+ trait_ref: ty::TraitRef::new(infcx.tcx, trait_did, [ty]),
constness: ty::BoundConstness::NotConst,
// Auto traits are positive
@@ -591,7 +591,7 @@ impl<'tcx> AutoTraitFinder<'tcx> {
fn evaluate_nested_obligations(
&self,
ty: Ty<'_>,
- nested: impl Iterator<Item = Obligation<'tcx, ty::Predicate<'tcx>>>,
+ nested: impl Iterator<Item = PredicateObligation<'tcx>>,
computed_preds: &mut FxIndexSet<ty::Predicate<'tcx>>,
fresh_preds: &mut FxHashSet<ty::Predicate<'tcx>>,
predicates: &mut VecDeque<ty::PolyTraitPredicate<'tcx>>,
@@ -796,13 +796,12 @@ impl<'tcx> AutoTraitFinder<'tcx> {
Ok(Some(valtree)) => Ok(selcx.tcx().mk_const(valtree, c.ty())),
Ok(None) => {
let tcx = self.tcx;
- let def_id = unevaluated.def.did;
let reported =
tcx.sess.emit_err(UnableToConstructConstantValue {
- span: tcx.def_span(def_id),
+ span: tcx.def_span(unevaluated.def),
unevaluated: unevaluated,
});
- Err(ErrorHandled::Reported(reported))
+ Err(ErrorHandled::Reported(reported.into()))
}
Err(err) => Err(err),
}
@@ -835,8 +834,10 @@ impl<'tcx> AutoTraitFinder<'tcx> {
| ty::PredicateKind::Subtype(..)
// FIXME(generic_const_exprs): you can absolutely add this as a where clauses
| ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+ | ty::PredicateKind::Coerce(..) => {}
+ ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("predicate should only exist in the environment: {bound_predicate:?}")
+ }
ty::PredicateKind::Ambiguous => return false,
};
}
diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs
index 20c2605f2..e8c5a8fab 100644
--- a/compiler/rustc_trait_selection/src/traits/coherence.rs
+++ b/compiler/rustc_trait_selection/src/traits/coherence.rs
@@ -17,9 +17,10 @@ use crate::traits::{
use rustc_data_structures::fx::FxIndexSet;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::{DefId, CRATE_DEF_ID, LOCAL_CRATE};
-use rustc_infer::infer::{DefineOpaqueTypes, DefiningAnchor, InferCtxt, TyCtxtInferExt};
+use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, TyCtxtInferExt};
use rustc_infer::traits::util;
use rustc_middle::traits::specialization_graph::OverlapMode;
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ImplSubject, Ty, TyCtxt, TypeVisitor};
@@ -322,7 +323,9 @@ fn negative_impl(tcx: TyCtxt<'_>, impl1_def_id: DefId, impl2_def_id: DefId) -> b
let selcx = &mut SelectionContext::new(&infcx);
let impl2_substs = infcx.fresh_substs_for_item(DUMMY_SP, impl2_def_id);
let (subject2, obligations) =
- impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs);
+ impl_subject_and_oblig(selcx, impl_env, impl2_def_id, impl2_substs, |_, _| {
+ ObligationCause::dummy()
+ });
!equate(&infcx, impl_env, subject1, subject2, obligations, impl1_def_id)
}
@@ -582,7 +585,7 @@ fn orphan_check_trait_ref<'tcx>(
trait_ref: ty::TraitRef<'tcx>,
in_crate: InCrate,
) -> Result<(), OrphanCheckErr<'tcx>> {
- if trait_ref.needs_infer() && trait_ref.needs_subst() {
+ if trait_ref.has_infer() && trait_ref.has_param() {
bug!(
"can't orphan check a trait ref with both params and inference variables {:?}",
trait_ref
@@ -673,7 +676,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
| ty::RawPtr(..)
| ty::Never
| ty::Tuple(..)
- | ty::Alias(ty::Projection, ..) => self.found_non_local_ty(ty),
+ | ty::Alias(ty::Projection | ty::Inherent, ..) => self.found_non_local_ty(ty),
ty::Param(..) => self.found_param_ty(ty),
@@ -704,7 +707,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OrphanChecker<'tcx> {
}
ty::Dynamic(tt, ..) => {
let principal = tt.principal().map(|p| p.def_id());
- if principal.map_or(false, |p| self.def_id_is_local(p)) {
+ if principal.is_some_and(|p| self.def_id_is_local(p)) {
ControlFlow::Break(OrphanCheckEarlyExit::LocalTy(ty))
} else {
self.found_non_local_ty(ty)
diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
index 345e84990..bd1ea43a7 100644
--- a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
+++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs
@@ -44,7 +44,7 @@ pub fn is_const_evaluatable<'tcx>(
let ct = tcx.expand_abstract_consts(unexpanded_ct);
let is_anon_ct = if let ty::ConstKind::Unevaluated(uv) = ct.kind() {
- tcx.def_kind(uv.def.did) == DefKind::AnonConst
+ tcx.def_kind(uv.def) == DefKind::AnonConst
} else {
false
};
@@ -79,7 +79,7 @@ pub fn is_const_evaluatable<'tcx>(
"Missing value for constant, but no error reported?",
)))
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
@@ -119,7 +119,7 @@ pub fn is_const_evaluatable<'tcx>(
tcx.sess
.struct_span_fatal(
// Slightly better span than just using `span` alone
- if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def.did) } else { span },
+ if span == rustc_span::DUMMY_SP { tcx.def_span(uv.def) } else { span },
"failed to evaluate generic const expression",
)
.note("the crate this constant originates from uses `#![feature(generic_const_exprs)]`")
@@ -147,7 +147,7 @@ pub fn is_const_evaluatable<'tcx>(
Err(err)
}
- Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e)),
+ Err(ErrorHandled::Reported(e)) => Err(NotConstEvaluatable::Error(e.into())),
Ok(_) => Ok(()),
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs
index 2beebe94b..2c5ffd664 100644
--- a/compiler/rustc_trait_selection/src/traits/engine.rs
+++ b/compiler/rustc_trait_selection/src/traits/engine.rs
@@ -14,11 +14,11 @@ use rustc_infer::infer::canonical::{
};
use rustc_infer::infer::outlives::env::OutlivesEnvironment;
use rustc_infer::infer::{DefineOpaqueTypes, InferCtxt, InferOk};
-use rustc_infer::traits::query::Fallible;
use rustc_infer::traits::{
FulfillmentError, Obligation, ObligationCause, PredicateObligation, TraitEngineExt as _,
};
use rustc_middle::arena::ArenaAllocatable;
+use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::error::TypeError;
use rustc_middle::ty::ToPredicate;
use rustc_middle::ty::TypeFoldable;
@@ -97,7 +97,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
def_id: DefId,
) {
let tcx = self.infcx.tcx;
- let trait_ref = tcx.mk_trait_ref(def_id, [ty]);
+ let trait_ref = ty::TraitRef::new(tcx, def_id, [ty]);
self.register_obligation(Obligation {
cause,
recursion_depth: 0,
@@ -235,7 +235,7 @@ impl<'a, 'tcx> ObligationCtxt<'a, 'tcx> {
&self,
inference_vars: CanonicalVarValues<'tcx>,
answer: T,
- ) -> Fallible<CanonicalQueryResponse<'tcx, T>>
+ ) -> Result<CanonicalQueryResponse<'tcx, T>, NoSolution>
where
T: Debug + TypeFoldable<TyCtxt<'tcx>>,
Canonical<'tcx, QueryResponse<'tcx, T>>: ArenaAllocatable<'tcx>,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
index 0475f24d8..7ab652761 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/ambiguity.rs
@@ -87,7 +87,7 @@ pub fn recompute_applicable_impls<'tcx>(
if let ty::PredicateKind::Clause(ty::Clause::Trait(trait_pred)) = kind.skip_binder()
&& param_env_candidate_may_apply(kind.rebind(trait_pred))
{
- if kind.rebind(trait_pred.trait_ref) == ty::TraitRef::identity(tcx, trait_pred.def_id()) {
+ if kind.rebind(trait_pred.trait_ref) == ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_pred.def_id())) {
ambiguities.push(Ambiguity::ParamEnv(tcx.def_span(trait_pred.def_id())))
} else {
ambiguities.push(Ambiguity::ParamEnv(span))
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
deleted file mode 100644
index 7e1dba4ed..000000000
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/method_chain.rs
+++ /dev/null
@@ -1,102 +0,0 @@
-use crate::infer::InferCtxt;
-
-use rustc_infer::infer::ObligationEmittingRelation;
-use rustc_infer::traits::PredicateObligations;
-use rustc_middle::ty::error::TypeError;
-use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
-use rustc_middle::ty::{self, Ty, TyCtxt};
-
-pub struct CollectAllMismatches<'a, 'tcx> {
- pub infcx: &'a InferCtxt<'tcx>,
- pub param_env: ty::ParamEnv<'tcx>,
- pub errors: Vec<TypeError<'tcx>>,
-}
-
-impl<'a, 'tcx> TypeRelation<'tcx> for CollectAllMismatches<'a, 'tcx> {
- fn tag(&self) -> &'static str {
- "CollectAllMismatches"
- }
-
- fn tcx(&self) -> TyCtxt<'tcx> {
- self.infcx.tcx
- }
-
- fn param_env(&self) -> ty::ParamEnv<'tcx> {
- self.param_env
- }
-
- fn a_is_expected(&self) -> bool {
- true
- }
-
- fn relate_with_variance<T: Relate<'tcx>>(
- &mut self,
- _: ty::Variance,
- _: ty::VarianceDiagInfo<'tcx>,
- a: T,
- b: T,
- ) -> RelateResult<'tcx, T> {
- self.relate(a, b)
- }
-
- fn regions(
- &mut self,
- a: ty::Region<'tcx>,
- _b: ty::Region<'tcx>,
- ) -> RelateResult<'tcx, ty::Region<'tcx>> {
- Ok(a)
- }
-
- fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> {
- self.infcx.probe(|_| {
- if a.is_ty_var() || b.is_ty_var() {
- Ok(a)
- } else {
- self.infcx.super_combine_tys(self, a, b).or_else(|e| {
- self.errors.push(e);
- Ok(a)
- })
- }
- })
- }
-
- fn consts(
- &mut self,
- a: ty::Const<'tcx>,
- b: ty::Const<'tcx>,
- ) -> RelateResult<'tcx, ty::Const<'tcx>> {
- self.infcx.probe(|_| {
- if a.is_ct_infer() || b.is_ct_infer() {
- Ok(a)
- } else {
- relate::super_relate_consts(self, a, b) // could do something similar here for constants!
- }
- })
- }
-
- fn binders<T: Relate<'tcx>>(
- &mut self,
- a: ty::Binder<'tcx, T>,
- b: ty::Binder<'tcx, T>,
- ) -> RelateResult<'tcx, ty::Binder<'tcx, T>> {
- Ok(a.rebind(self.relate(a.skip_binder(), b.skip_binder())?))
- }
-}
-
-impl<'tcx> ObligationEmittingRelation<'tcx> for CollectAllMismatches<'_, 'tcx> {
- fn alias_relate_direction(&self) -> ty::AliasRelationDirection {
- // FIXME(deferred_projection_equality): We really should get rid of this relation.
- ty::AliasRelationDirection::Equate
- }
-
- fn register_obligations(&mut self, _obligations: PredicateObligations<'tcx>) {
- // FIXME(deferred_projection_equality)
- }
-
- fn register_predicates(
- &mut self,
- _obligations: impl IntoIterator<Item: ty::ToPredicate<'tcx>>,
- ) {
- // FIXME(deferred_projection_equality)
- }
-}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
index 1b741b730..a10ececbb 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs
@@ -1,5 +1,4 @@
mod ambiguity;
-pub mod method_chain;
pub mod on_unimplemented;
pub mod suggestions;
@@ -15,8 +14,7 @@ use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use crate::traits::query::normalize::QueryNormalizeExt as _;
use crate::traits::specialize::to_pretty_impl_header;
use crate::traits::NormalizeExt;
-use on_unimplemented::OnUnimplementedNote;
-use on_unimplemented::TypeErrCtxtExt as _;
+use on_unimplemented::{AppendConstMessage, OnUnimplementedNote, TypeErrCtxtExt as _};
use rustc_data_structures::fx::{FxHashMap, FxIndexMap};
use rustc_errors::{
pluralize, struct_span_err, Applicability, Diagnostic, DiagnosticBuilder, ErrorGuaranteed,
@@ -30,9 +28,9 @@ use rustc_hir::{GenericParam, Item, Node};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::{InferOk, TypeTrace};
use rustc_middle::traits::select::OverflowError;
+use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::ty::abstract_const::NotConstEvaluatable;
use rustc_middle::ty::error::{ExpectedFound, TypeError};
-use rustc_middle::ty::fast_reject::TreatProjections;
use rustc_middle::ty::fold::{TypeFolder, TypeSuperFoldable};
use rustc_middle::ty::print::{with_forced_trimmed_paths, FmtPrinter, Print};
use rustc_middle::ty::{
@@ -273,7 +271,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
let underscores = vec!["_"; expected_args.len()].join(", ");
err.span_suggestion_verbose(
closure_arg_span.unwrap_or(found_span),
- &format!(
+ format!(
"consider changing the closure to take and ignore the expected argument{}",
pluralize!(expected_args.len())
),
@@ -360,7 +358,7 @@ impl<'tcx> InferCtxtExt<'tcx> for InferCtxt<'tcx> {
span: DUMMY_SP,
kind: TypeVariableOriginKind::MiscVariable,
});
- let trait_ref = self.tcx.mk_trait_ref(trait_def_id, [ty.skip_binder(), var]);
+ let trait_ref = ty::TraitRef::new(self.tcx, trait_def_id, [ty.skip_binder(), var]);
let obligation = Obligation::new(
self.tcx,
ObligationCause::dummy(),
@@ -439,7 +437,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// 1) strictly implied by another error.
// 2) implied by an error with a smaller index.
for error2 in error_set {
- if error2.index.map_or(false, |index2| is_suppressed[index2]) {
+ if error2.index.is_some_and(|index2| is_suppressed[index2]) {
// Avoid errors being suppressed by already-suppressed
// errors, to prevent all errors from being suppressed
// at once.
@@ -467,7 +465,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fullfillment errors")
+ self.tcx.sess.delay_span_bug(DUMMY_SP, "expected fulfillment errors")
}
/// Reports that an overflow has occurred and halts compilation. We
@@ -561,6 +559,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
suggest_increasing_limit,
|err| {
self.note_obligation_cause_code(
+ obligation.cause.body_id,
err,
predicate,
obligation.param_env,
@@ -577,7 +576,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Limit(0) => Limit(2),
limit => limit * 2,
};
- err.help(&format!(
+ err.help(format!(
"consider increasing the recursion limit by adding a \
`#![recursion_limit = \"{}\"]` attribute to your crate (`{}`)",
suggested_limit,
@@ -707,42 +706,25 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
conversion on the error value using the `From` trait"
.to_owned(),
),
- Some(None),
+ Some(AppendConstMessage::Default),
)
} else {
(message, note, append_const_msg)
};
- let err_msg = message
- .and_then(|cannot_do_this| {
- match (predicate_is_const, append_const_msg) {
- // do nothing if predicate is not const
- (false, _) => Some(cannot_do_this),
- // suggested using default post message
- (true, Some(None)) => {
- Some(format!("{cannot_do_this} in const contexts"))
- }
- // overridden post message
- (true, Some(Some(post_message))) => {
- Some(format!("{cannot_do_this}{post_message}"))
- }
- // fallback to generic message
- (true, None) => None,
- }
- })
- .unwrap_or_else(|| {
- format!(
- "the trait bound `{}` is not satisfied{}",
- trait_predicate, post_message,
- )
- });
+ let err_msg = self.get_standard_error_message(
+ &trait_predicate,
+ message,
+ predicate_is_const,
+ append_const_msg,
+ post_message,
+ );
let (err_msg, safe_transmute_explanation) = if Some(trait_ref.def_id())
== self.tcx.lang_items().transmute_trait()
{
// Recompute the safe transmute reason and use that for the error reporting
self.get_safe_transmute_error_and_reason(
- trait_predicate,
obligation.clone(),
trait_ref,
span,
@@ -756,7 +738,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if is_try_conversion && let Some(ret_span) = self.return_type_span(&obligation) {
err.span_label(
ret_span,
- &format!(
+ format!(
"expected `{}` because of this",
trait_ref.skip_binder().self_ty()
),
@@ -764,22 +746,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
if Some(trait_ref.def_id()) == tcx.lang_items().tuple_trait() {
- match obligation.cause.code().peel_derives() {
- ObligationCauseCode::RustCall => {
- err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
- }
- ObligationCauseCode::BindingObligation(def_id, _)
- | ObligationCauseCode::ItemObligation(def_id)
- if tcx.is_fn_trait(*def_id) =>
- {
- err.code(rustc_errors::error_code!(E0059));
- err.set_primary_message(format!(
- "type parameter to bare `{}` trait must be a tuple",
- tcx.def_path_str(*def_id)
- ));
- }
- _ => {}
- }
+ self.add_tuple_trait_message(
+ &obligation.cause.code().peel_derives(),
+ &mut err,
+ );
}
if Some(trait_ref.def_id()) == tcx.lang_items().drop_trait()
@@ -789,33 +759,13 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("See <https://github.com/rust-lang/rust/pull/94901> for more details");
}
- let explanation = if let ObligationCauseCode::MainFunctionType =
- obligation.cause.code()
- {
- "consider using `()`, or a `Result`".to_owned()
- } else {
- let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
- ty::FnDef(_, _) => Some("fn item"),
- ty::Closure(_, _) => Some("closure"),
- _ => None,
- };
+ let explanation = get_explanation_based_on_obligation(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ pre_message,
+ );
- match ty_desc {
- Some(desc) => format!(
- "{}the trait `{}` is not implemented for {} `{}`",
- pre_message,
- trait_predicate.print_modifiers_and_trait_path(),
- desc,
- trait_ref.skip_binder().self_ty(),
- ),
- None => format!(
- "{}the trait `{}` is not implemented for `{}`",
- pre_message,
- trait_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
- ),
- }
- };
self.check_for_binding_assigned_block_without_tail_expression(
&obligation,
&mut err,
@@ -831,7 +781,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.emit();
return;
}
- if let Some(ref s) = label {
+ if let Some(s) = label {
// If it has a custom `#[rustc_on_unimplemented]`
// error message, let's display it as the label!
err.span_label(span, s);
@@ -839,7 +789,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// When the self type is a type param We don't need to "the trait
// `std::marker::Sized` is not implemented for `T`" as we will point
// at the type param with a label to suggest constraining it.
- err.help(&explanation);
+ err.help(explanation);
}
} else if let Some(custom_explanation) = safe_transmute_explanation {
err.span_label(span, custom_explanation);
@@ -847,42 +797,36 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_label(span, explanation);
}
- if let ObligationCauseCode::ObjectCastObligation(concrete_ty, obj_ty) = obligation.cause.code().peel_derives() &&
- Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
- self.suggest_borrowing_for_object_cast(&mut err, &root_obligation, *concrete_ty, *obj_ty);
- }
-
- let mut unsatisfied_const = false;
- if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
- let non_const_predicate = trait_ref.without_const();
- let non_const_obligation = Obligation {
- cause: obligation.cause.clone(),
- param_env: obligation.param_env.without_const(),
- predicate: non_const_predicate.to_predicate(tcx),
- recursion_depth: obligation.recursion_depth,
- };
- if self.predicate_may_hold(&non_const_obligation) {
- unsatisfied_const = true;
- err.span_note(
- span,
- &format!(
- "the trait `{}` is implemented for `{}`, \
- but that implementation is not `const`",
- non_const_predicate.print_modifiers_and_trait_path(),
- trait_ref.skip_binder().self_ty(),
- ),
+ if let ObligationCauseCode::Coercion { source, target } =
+ *obligation.cause.code().peel_derives()
+ {
+ if Some(trait_ref.def_id()) == self.tcx.lang_items().sized_trait() {
+ self.suggest_borrowing_for_object_cast(
+ &mut err,
+ &root_obligation,
+ source,
+ target,
);
}
}
+ let UnsatisfiedConst(unsatisfied_const) = self
+ .maybe_add_note_for_unsatisfied_const(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ &mut err,
+ span,
+ );
+
if let Some((msg, span)) = type_def {
- err.span_label(span, &msg);
+ err.span_label(span, msg);
}
- if let Some(ref s) = note {
+ if let Some(s) = note {
// If it has a custom `#[rustc_on_unimplemented]` note, let's display it
- err.note(s.as_str());
+ err.note(s);
}
- if let Some(ref s) = parent_label {
+ if let Some(s) = parent_label {
let body = obligation.cause.body_id;
err.span_label(tcx.def_span(body), s);
}
@@ -941,7 +885,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
return;
}
- if self.suggest_impl_trait(&mut err, span, &obligation, trait_predicate) {
+ if self.suggest_impl_trait(&mut err, &obligation, trait_predicate) {
err.emit();
return;
}
@@ -971,137 +915,16 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
}
- let body_def_id = obligation.cause.body_id;
- // Try to report a help message
- if is_fn_trait
- && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
- obligation.param_env,
- trait_ref.self_ty(),
- trait_predicate.skip_binder().constness,
- trait_predicate.skip_binder().polarity,
- )
- {
- // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
- // suggestion to add trait bounds for the type, since we only typically implement
- // these traits once.
-
- // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
- // to implement.
- let selected_kind =
- self.tcx.fn_trait_kind_from_def_id(trait_ref.def_id())
- .expect("expected to map DefId to ClosureKind");
- if !implemented_kind.extends(selected_kind) {
- err.note(
- &format!(
- "`{}` implements `{}`, but it must implement `{}`, which is more general",
- trait_ref.skip_binder().self_ty(),
- implemented_kind,
- selected_kind
- )
- );
- }
-
- // Note any argument mismatches
- let given_ty = params.skip_binder();
- let expected_ty = trait_ref.skip_binder().substs.type_at(1);
- if let ty::Tuple(given) = given_ty.kind()
- && let ty::Tuple(expected) = expected_ty.kind()
- {
- if expected.len() != given.len() {
- // Note number of types that were expected and given
- err.note(
- &format!(
- "expected a closure taking {} argument{}, but one taking {} argument{} was given",
- given.len(),
- pluralize!(given.len()),
- expected.len(),
- pluralize!(expected.len()),
- )
- );
- } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
- // Print type mismatch
- let (expected_args, given_args) =
- self.cmp(given_ty, expected_ty);
- err.note_expected_found(
- &"a closure with arguments",
- expected_args,
- &"a closure with arguments",
- given_args,
- );
- }
- }
- } else if !trait_ref.has_non_region_infer()
- && self.predicate_can_apply(obligation.param_env, trait_predicate)
- {
- // If a where-clause may be useful, remind the
- // user that they can add it.
- //
- // don't display an on-unimplemented note, as
- // these notes will often be of the form
- // "the type `T` can't be frobnicated"
- // which is somewhat confusing.
- self.suggest_restricting_param_bound(
- &mut err,
- trait_predicate,
- None,
- obligation.cause.body_id,
- );
- } else if !suggested && !unsatisfied_const {
- // Can't show anything else useful, try to find similar impls.
- let impl_candidates = self.find_similar_impl_candidates(trait_predicate);
- if !self.report_similar_impl_candidates(
- &impl_candidates,
- trait_ref,
- body_def_id,
- &mut err,
- true,
- ) {
- // This is *almost* equivalent to
- // `obligation.cause.code().peel_derives()`, but it gives us the
- // trait predicate for that corresponding root obligation. This
- // lets us get a derived obligation from a type parameter, like
- // when calling `string.strip_suffix(p)` where `p` is *not* an
- // implementer of `Pattern<'_>`.
- let mut code = obligation.cause.code();
- let mut trait_pred = trait_predicate;
- let mut peeled = false;
- while let Some((parent_code, parent_trait_pred)) = code.parent() {
- code = parent_code;
- if let Some(parent_trait_pred) = parent_trait_pred {
- trait_pred = parent_trait_pred;
- peeled = true;
- }
- }
- let def_id = trait_pred.def_id();
- // Mention *all* the `impl`s for the *top most* obligation, the
- // user might have meant to use one of them, if any found. We skip
- // auto-traits or fundamental traits that might not be exactly what
- // the user might expect to be presented with. Instead this is
- // useful for less general traits.
- if peeled
- && !self.tcx.trait_is_auto(def_id)
- && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
- {
- let trait_ref = trait_pred.to_poly_trait_ref();
- let impl_candidates =
- self.find_similar_impl_candidates(trait_pred);
- self.report_similar_impl_candidates(
- &impl_candidates,
- trait_ref,
- body_def_id,
- &mut err,
- true,
- );
- }
- }
-
- self.maybe_suggest_convert_to_slice(
- &mut err,
- trait_ref,
- impl_candidates.as_slice(),
- span,
- );
- }
+ self.try_to_add_help_message(
+ &obligation,
+ trait_ref,
+ &trait_predicate,
+ &mut err,
+ span,
+ is_fn_trait,
+ suggested,
+ unsatisfied_const,
+ );
// Changing mutability doesn't make a difference to whether we have
// an `Unsize` impl (Fixes ICE in #71036)
@@ -1196,59 +1019,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::ClosureKind(closure_def_id, closure_substs, kind) => {
let found_kind = self.closure_kind(closure_substs).unwrap();
- let closure_span = self.tcx.def_span(closure_def_id);
- let mut err = struct_span_err!(
- self.tcx.sess,
- closure_span,
- E0525,
- "expected a closure that implements the `{}` trait, \
- but this closure only implements `{}`",
- kind,
- found_kind
- );
-
- err.span_label(
- closure_span,
- format!("this closure implements `{}`, not `{}`", found_kind, kind),
- );
- err.span_label(
- obligation.cause.span,
- format!("the requirement to implement `{}` derives from here", kind),
- );
-
- // Additional context information explaining why the closure only implements
- // a particular trait.
- if let Some(typeck_results) = &self.typeck_results {
- let hir_id = self
- .tcx
- .hir()
- .local_def_id_to_hir_id(closure_def_id.expect_local());
- match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
- (ty::ClosureKind::FnOnce, Some((span, place))) => {
- err.span_label(
- *span,
- format!(
- "closure is `FnOnce` because it moves the \
- variable `{}` out of its environment",
- ty::place_to_string_for_capture(tcx, place)
- ),
- );
- }
- (ty::ClosureKind::FnMut, Some((span, place))) => {
- err.span_label(
- *span,
- format!(
- "closure is `FnMut` because it mutates the \
- variable `{}` here",
- ty::place_to_string_for_capture(tcx, place)
- ),
- );
- }
- _ => {}
- }
- }
-
- err
+ self.report_closure_error(&obligation, closure_def_id, found_kind, kind)
}
ty::PredicateKind::WellFormed(ty) => {
@@ -1266,7 +1037,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// which bounds actually failed to hold.
self.tcx.sess.struct_span_err(
span,
- &format!("the type `{}` is not well-formed", ty),
+ format!("the type `{}` is not well-formed", ty),
)
}
}
@@ -1309,7 +1080,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(ct, ty)) => {
let mut diag = self.tcx.sess.struct_span_err(
span,
- &format!("the constant `{}` is not of type `{}`", ct, ty),
+ format!("the constant `{}` is not of type `{}`", ct, ty),
);
self.note_type_err(
&mut diag,
@@ -1325,121 +1096,29 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- OutputTypeParameterMismatch(
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
found_trait_ref,
expected_trait_ref,
- terr @ TypeError::CyclicTy(_),
- ) => {
- let self_ty = found_trait_ref.self_ty().skip_binder();
- let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
- (
- ObligationCause::dummy_with_span(tcx.def_span(def_id)),
- TypeError::CyclicTy(self_ty),
- )
- } else {
- (obligation.cause.clone(), terr)
- };
- self.report_and_explain_type_error(
- TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
- terr,
- )
- }
- OutputTypeParameterMismatch(found_trait_ref, expected_trait_ref, _) => {
- let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
- let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
-
- if expected_trait_ref.self_ty().references_error() {
- return;
- }
-
- let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
- return;
- };
-
- let found_did = match *found_trait_ty.kind() {
- ty::Closure(did, _)
- | ty::Foreign(did)
- | ty::FnDef(did, _)
- | ty::Generator(did, ..) => Some(did),
- ty::Adt(def, _) => Some(def.did()),
- _ => None,
- };
-
- let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
- let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
-
- if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
- // We check closures twice, with obligations flowing in different directions,
- // but we want to complain about them only once.
- return;
- }
-
- self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
-
- let mut not_tupled = false;
-
- let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
- ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
- _ => {
- not_tupled = true;
- vec![ArgKind::empty()]
- }
- };
-
- let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
- let expected = match expected_ty.kind() {
- ty::Tuple(ref tys) => {
- tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
- }
- _ => {
- not_tupled = true;
- vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
- }
- };
-
- // If this is a `Fn` family trait and either the expected or found
- // is not tupled, then fall back to just a regular mismatch error.
- // This shouldn't be common unless manually implementing one of the
- // traits manually, but don't make it more confusing when it does
- // happen.
- if Some(expected_trait_ref.def_id()) != tcx.lang_items().gen_trait() && not_tupled {
- self.report_and_explain_type_error(
- TypeTrace::poly_trait_refs(
- &obligation.cause,
- true,
- expected_trait_ref,
- found_trait_ref,
- ),
- ty::error::TypeError::Mismatch,
- )
- } else if found.len() == expected.len() {
- self.report_closure_arg_mismatch(
- span,
- found_span,
- found_trait_ref,
- expected_trait_ref,
- obligation.cause.code(),
- found_node,
- obligation.param_env,
- )
- } else {
- let (closure_span, closure_arg_span, found) = found_did
- .and_then(|did| {
- let node = self.tcx.hir().get_if_local(did)?;
- let (found_span, closure_arg_span, found) =
- self.get_fn_like_arguments(node)?;
- Some((Some(found_span), closure_arg_span, found))
- })
- .unwrap_or((found_span, None, found));
-
- self.report_arg_count_mismatch(
- span,
- closure_span,
- expected,
- found,
- found_trait_ty.is_closure(),
- closure_arg_span,
- )
+ terr: terr @ TypeError::CyclicTy(_),
+ }) => self.report_type_parameter_mismatch_cyclic_type_error(
+ &obligation,
+ found_trait_ref,
+ expected_trait_ref,
+ terr,
+ ),
+ OutputTypeParameterMismatch(box SelectionOutputTypeParameterMismatch {
+ found_trait_ref,
+ expected_trait_ref,
+ terr: _,
+ }) => {
+ match self.report_type_parameter_mismatch_error(
+ &obligation,
+ span,
+ found_trait_ref,
+ expected_trait_ref,
+ ) {
+ Some(err) => err,
+ None => return,
}
}
@@ -1454,45 +1133,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
)
}
SelectionError::NotConstEvaluatable(NotConstEvaluatable::MentionsParam) => {
- if !self.tcx.features().generic_const_exprs {
- let mut err = self.tcx.sess.struct_span_err(
- span,
- "constant expression depends on a generic parameter",
- );
- // FIXME(const_generics): we should suggest to the user how they can resolve this
- // issue. However, this is currently not actually possible
- // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
- //
- // Note that with `feature(generic_const_exprs)` this case should not
- // be reachable.
- err.note("this may fail depending on what value the parameter takes");
- err.emit();
- return;
- }
-
- match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::ConstEvaluatable(ct) => {
- let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
- bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
- };
- let mut err =
- self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
- let const_span = self.tcx.def_span(uv.def.did);
- match self.tcx.sess.source_map().span_to_snippet(const_span) {
- Ok(snippet) => err.help(&format!(
- "try adding a `where` bound using this expression: `where [(); {}]:`",
- snippet
- )),
- _ => err.help("consider adding a `where` bound using this expression"),
- };
- err
- }
- _ => {
- span_bug!(
- span,
- "unexpected non-ConstEvaluatable predicate, this should not be reachable"
- )
- }
+ match self.report_not_const_evaluatable_error(&obligation, span) {
+ Some(err) => err,
+ None => return,
}
}
@@ -1564,6 +1207,14 @@ trait InferCtxtPrivExt<'tcx> {
other: bool,
) -> bool;
+ fn report_similar_impl_candidates_for_root_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ body_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ );
+
/// Gets the parent trait chain start
fn get_parent_trait_ref(
&self,
@@ -1627,13 +1278,86 @@ trait InferCtxtPrivExt<'tcx> {
cause_code: &ObligationCauseCode<'tcx>,
) -> bool;
+ fn get_standard_error_message(
+ &self,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ message: Option<String>,
+ predicate_is_const: bool,
+ append_const_msg: Option<AppendConstMessage>,
+ post_message: String,
+ ) -> String;
+
fn get_safe_transmute_error_and_reason(
&self,
- trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
- obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
) -> (String, Option<String>);
+
+ fn add_tuple_trait_message(
+ &self,
+ obligation_cause_code: &ObligationCauseCode<'tcx>,
+ err: &mut Diagnostic,
+ );
+
+ fn try_to_add_help_message(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ is_fn_trait: bool,
+ suggested: bool,
+ unsatisfied_const: bool,
+ );
+
+ fn add_help_message_for_fn_trait(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ err: &mut Diagnostic,
+ implemented_kind: ty::ClosureKind,
+ params: ty::Binder<'tcx, Ty<'tcx>>,
+ );
+
+ fn maybe_add_note_for_unsatisfied_const(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ ) -> UnsatisfiedConst;
+
+ fn report_closure_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ closure_def_id: DefId,
+ found_kind: ty::ClosureKind,
+ kind: ty::ClosureKind,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ fn report_type_parameter_mismatch_cyclic_type_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed>;
+
+ fn report_type_parameter_mismatch_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
+
+ fn report_not_const_evaluatable_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>>;
}
impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
@@ -1720,6 +1444,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::ExprItemObligation(..) = code
{
self.note_obligation_cause_code(
+ error.obligation.cause.body_id,
&mut diag,
error.obligation.predicate,
error.obligation.param_env,
@@ -1773,7 +1498,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.tcx
.mk_const(
ty::UnevaluatedConst {
- def: ty::WithOptConstParam::unknown(data.projection_ty.def_id),
+ def: data.projection_ty.def_id,
substs: data.projection_ty.substs,
},
ct.ty(),
@@ -1793,7 +1518,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::BindingObligation(_, _)
| ObligationCauseCode::ExprItemObligation(..)
| ObligationCauseCode::ExprBindingObligation(..)
- | ObligationCauseCode::ObjectCastObligation(..)
+ | ObligationCauseCode::Coercion { .. }
| ObligationCauseCode::OpaqueType
);
@@ -1838,57 +1563,61 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
});
let mut diag = struct_span_err!(self.tcx.sess, obligation.cause.span, E0271, "{msg}");
- let secondary_span = match predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(proj)) => self
- .tcx
- .opt_associated_item(proj.projection_ty.def_id)
- .and_then(|trait_assoc_item| {
- self.tcx
- .trait_of_item(proj.projection_ty.def_id)
- .map(|id| (trait_assoc_item, id))
- })
- .and_then(|(trait_assoc_item, id)| {
- let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
- self.tcx.find_map_relevant_impl(
- id,
- proj.projection_ty.self_ty(),
- TreatProjections::ForLookup,
- |did| {
- self.tcx
- .associated_items(did)
- .in_definition_order()
- .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident)
- },
- )
- })
- .and_then(|item| match self.tcx.hir().get_if_local(item.def_id) {
- Some(
- hir::Node::TraitItem(hir::TraitItem {
- kind: hir::TraitItemKind::Type(_, Some(ty)),
- ..
- })
- | hir::Node::ImplItem(hir::ImplItem {
- kind: hir::ImplItemKind::Type(ty),
- ..
- }),
- ) => Some((
- ty.span,
- with_forced_trimmed_paths!(format!(
- "type mismatch resolving `{}`",
- self.resolve_vars_if_possible(predicate)
- .print(FmtPrinter::new_with_limit(
- self.tcx,
- Namespace::TypeNS,
- rustc_session::Limit(5),
- ))
- .unwrap()
- .into_buffer()
- )),
+ let secondary_span = (|| {
+ let ty::PredicateKind::Clause(ty::Clause::Projection(proj)) =
+ predicate.kind().skip_binder()
+ else {
+ return None;
+ };
+
+ let trait_assoc_item = self.tcx.opt_associated_item(proj.projection_ty.def_id)?;
+ let trait_assoc_ident = trait_assoc_item.ident(self.tcx);
+
+ let mut associated_items = vec![];
+ self.tcx.for_each_relevant_impl(
+ self.tcx.trait_of_item(proj.projection_ty.def_id)?,
+ proj.projection_ty.self_ty(),
+ |impl_def_id| {
+ associated_items.extend(
+ self.tcx
+ .associated_items(impl_def_id)
+ .in_definition_order()
+ .find(|assoc| assoc.ident(self.tcx) == trait_assoc_ident),
+ );
+ },
+ );
+
+ let [associated_item]: &[ty::AssocItem] = &associated_items[..] else {
+ return None;
+ };
+ match self.tcx.hir().get_if_local(associated_item.def_id) {
+ Some(
+ hir::Node::TraitItem(hir::TraitItem {
+ kind: hir::TraitItemKind::Type(_, Some(ty)),
+ ..
+ })
+ | hir::Node::ImplItem(hir::ImplItem {
+ kind: hir::ImplItemKind::Type(ty),
+ ..
+ }),
+ ) => Some((
+ ty.span,
+ with_forced_trimmed_paths!(format!(
+ "type mismatch resolving `{}`",
+ self.resolve_vars_if_possible(predicate)
+ .print(FmtPrinter::new_with_limit(
+ self.tcx,
+ Namespace::TypeNS,
+ rustc_session::Limit(5),
+ ))
+ .unwrap()
+ .into_buffer()
)),
- _ => None,
- }),
- _ => None,
- };
+ )),
+ _ => None,
+ }
+ })();
+
self.note_type_err(
&mut diag,
&obligation.cause,
@@ -1971,13 +1700,14 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ty::Tuple(..) => Some(10),
ty::Param(..) => Some(11),
ty::Alias(ty::Projection, ..) => Some(12),
- ty::Alias(ty::Opaque, ..) => Some(13),
- ty::Never => Some(14),
- ty::Adt(..) => Some(15),
- ty::Generator(..) => Some(16),
- ty::Foreign(..) => Some(17),
- ty::GeneratorWitness(..) => Some(18),
- ty::GeneratorWitnessMIR(..) => Some(19),
+ ty::Alias(ty::Inherent, ..) => Some(13),
+ ty::Alias(ty::Opaque, ..) => Some(14),
+ ty::Never => Some(15),
+ ty::Adt(..) => Some(16),
+ ty::Generator(..) => Some(17),
+ ty::Foreign(..) => Some(18),
+ ty::GeneratorWitness(..) => Some(19),
+ ty::GeneratorWitnessMIR(..) => Some(20),
ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => None,
}
}
@@ -2058,7 +1788,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if candidates.iter().any(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. })) {
// If any of the candidates is a perfect match, we don't want to show all of them.
// This is particularly relevant for the case of numeric types (as they all have the
- // same cathegory).
+ // same category).
candidates.retain(|c| matches!(c.similarity, CandidateSimilarity::Exact { .. }));
}
candidates
@@ -2120,7 +1850,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
candidates.sort();
candidates.dedup();
let end = if candidates.len() <= 9 { candidates.len() } else { 8 };
- err.help(&format!(
+ err.help(format!(
"the following {other}types implement trait `{}`:{}{}",
trait_ref.print_only_trait_path(),
candidates[..end].join(""),
@@ -2197,6 +1927,51 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
report(normalized_impl_candidates, err)
}
+ fn report_similar_impl_candidates_for_root_obligation(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
+ body_def_id: LocalDefId,
+ err: &mut Diagnostic,
+ ) {
+ // This is *almost* equivalent to
+ // `obligation.cause.code().peel_derives()`, but it gives us the
+ // trait predicate for that corresponding root obligation. This
+ // lets us get a derived obligation from a type parameter, like
+ // when calling `string.strip_suffix(p)` where `p` is *not* an
+ // implementer of `Pattern<'_>`.
+ let mut code = obligation.cause.code();
+ let mut trait_pred = trait_predicate;
+ let mut peeled = false;
+ while let Some((parent_code, parent_trait_pred)) = code.parent() {
+ code = parent_code;
+ if let Some(parent_trait_pred) = parent_trait_pred {
+ trait_pred = parent_trait_pred;
+ peeled = true;
+ }
+ }
+ let def_id = trait_pred.def_id();
+ // Mention *all* the `impl`s for the *top most* obligation, the
+ // user might have meant to use one of them, if any found. We skip
+ // auto-traits or fundamental traits that might not be exactly what
+ // the user might expect to be presented with. Instead this is
+ // useful for less general traits.
+ if peeled
+ && !self.tcx.trait_is_auto(def_id)
+ && !self.tcx.lang_items().iter().any(|(_, id)| id == def_id)
+ {
+ let trait_ref = trait_pred.to_poly_trait_ref();
+ let impl_candidates = self.find_similar_impl_candidates(trait_pred);
+ self.report_similar_impl_candidates(
+ &impl_candidates,
+ trait_ref,
+ body_def_id,
+ err,
+ true,
+ );
+ }
+ }
+
/// Gets the parent trait chain start
fn get_parent_trait_ref(
&self,
@@ -2230,14 +2005,18 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
trait_ref: &ty::PolyTraitRef<'tcx>,
) -> bool {
- let get_trait_impl = |trait_def_id| {
- self.tcx.find_map_relevant_impl(
+ let get_trait_impls = |trait_def_id| {
+ let mut trait_impls = vec![];
+ self.tcx.for_each_relevant_impl(
trait_def_id,
trait_ref.skip_binder().self_ty(),
- TreatProjections::ForLookup,
- Some,
- )
+ |impl_def_id| {
+ trait_impls.push(impl_def_id);
+ },
+ );
+ trait_impls
};
+
let required_trait_path = self.tcx.def_path_str(trait_ref.def_id());
let traits_with_same_path: std::collections::BTreeSet<_> = self
.tcx
@@ -2247,17 +2026,23 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.collect();
let mut suggested = false;
for trait_with_same_path in traits_with_same_path {
- if let Some(impl_def_id) = get_trait_impl(trait_with_same_path) {
- let impl_span = self.tcx.def_span(impl_def_id);
- err.span_help(impl_span, "trait impl with same name found");
- let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
- let crate_msg = format!(
- "perhaps two different versions of crate `{}` are being used?",
- trait_crate
- );
- err.note(&crate_msg);
- suggested = true;
+ let trait_impls = get_trait_impls(trait_with_same_path);
+ if trait_impls.is_empty() {
+ continue;
}
+ let impl_spans: Vec<_> =
+ trait_impls.iter().map(|impl_def_id| self.tcx.def_span(*impl_def_id)).collect();
+ err.span_help(
+ impl_spans,
+ format!("trait impl{} with same name found", pluralize!(trait_impls.len())),
+ );
+ let trait_crate = self.tcx.crate_name(trait_with_same_path.krate);
+ let crate_msg = format!(
+ "perhaps two different versions of crate `{}` are being used?",
+ trait_crate
+ );
+ err.note(crate_msg);
+ suggested = true;
}
suggested
}
@@ -2388,7 +2173,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
return;
}
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
let impl_candidates = self.find_similar_impl_candidates(
predicate.to_opt_poly_trait_pred().unwrap(),
);
@@ -2408,7 +2193,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
return;
}
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
}
}
@@ -2453,9 +2238,9 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.cancel();
err = self.tcx.sess.struct_span_err_with_code(
span,
- &format!(
+ format!(
"cannot {verb} associated {noun} on trait without specifying the corresponding `impl` type",
- ),
+ ),
rustc_errors::error_code!(E0790),
);
@@ -2562,7 +2347,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
ErrorCode::E0284,
true,
);
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
err
} else {
// If we can't find a substitution, just print a generic error
@@ -2573,7 +2358,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
}
@@ -2601,7 +2386,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
}
@@ -2616,7 +2401,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"type annotations needed: cannot satisfy `{}`",
predicate,
);
- err.span_label(span, &format!("cannot satisfy `{}`", predicate));
+ err.span_label(span, format!("cannot satisfy `{}`", predicate));
err
}
};
@@ -2689,13 +2474,13 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
match (spans.len(), crates.len(), crate_names.len()) {
(0, 0, 0) => {
- err.note(&format!("cannot satisfy `{}`", predicate));
+ err.note(format!("cannot satisfy `{}`", predicate));
}
(0, _, 1) => {
- err.note(&format!("{} in the `{}` crate{}", msg, crates[0], post,));
+ err.note(format!("{} in the `{}` crate{}", msg, crates[0], post,));
}
(0, _, _) => {
- err.note(&format!(
+ err.note(format!(
"{} in the following crates: {}{}",
msg,
crate_names.join(", "),
@@ -2704,19 +2489,17 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
(_, 0, 0) => {
let span: MultiSpan = spans.into();
- err.span_note(span, &msg);
+ err.span_note(span, msg);
}
(_, 1, 1) => {
let span: MultiSpan = spans.into();
- err.span_note(span, &msg);
- err.note(
- &format!("and another `impl` found in the `{}` crate{}", crates[0], post,),
- );
+ err.span_note(span, msg);
+ err.note(format!("and another `impl` found in the `{}` crate{}", crates[0], post,));
}
_ => {
let span: MultiSpan = spans.into();
- err.span_note(span, &msg);
- err.note(&format!(
+ err.span_note(span, msg);
+ err.note(format!(
"and more `impl`s found in the following crates: {}{}",
crate_names.join(", "),
post,
@@ -2776,6 +2559,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// message, and fall back to regular note otherwise.
if !self.maybe_note_obligation_cause_for_async_await(err, obligation) {
self.note_obligation_cause_code(
+ obligation.cause.body_id,
err,
obligation.predicate,
obligation.param_env,
@@ -2887,7 +2671,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_help(
multispan,
- &format!(
+ format!(
"you could relax the implicit `Sized` bound on `{T}` if it were \
used through indirection like `&{T}` or `Box<{T}>`",
T = param.name.ident(),
@@ -2919,20 +2703,52 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
false
}
+ fn get_standard_error_message(
+ &self,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ message: Option<String>,
+ predicate_is_const: bool,
+ append_const_msg: Option<AppendConstMessage>,
+ post_message: String,
+ ) -> String {
+ message
+ .and_then(|cannot_do_this| {
+ match (predicate_is_const, append_const_msg) {
+ // do nothing if predicate is not const
+ (false, _) => Some(cannot_do_this),
+ // suggested using default post message
+ (true, Some(AppendConstMessage::Default)) => {
+ Some(format!("{cannot_do_this} in const contexts"))
+ }
+ // overridden post message
+ (true, Some(AppendConstMessage::Custom(custom_msg))) => {
+ Some(format!("{cannot_do_this}{custom_msg}"))
+ }
+ // fallback to generic message
+ (true, None) => None,
+ }
+ })
+ .unwrap_or_else(|| {
+ format!("the trait bound `{}` is not satisfied{}", trait_predicate, post_message)
+ })
+ }
+
fn get_safe_transmute_error_and_reason(
&self,
- trait_predicate: ty::Binder<'tcx, ty::TraitPredicate<'tcx>>,
- obligation: Obligation<'tcx, ty::Predicate<'tcx>>,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ obligation: PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
span: Span,
) -> (String, Option<String>) {
- let src_and_dst = trait_predicate.map_bound(|p| rustc_transmute::Types {
- dst: p.trait_ref.substs.type_at(0),
- src: p.trait_ref.substs.type_at(1),
- });
- let scope = trait_ref.skip_binder().substs.type_at(2);
+ // Erase regions because layout code doesn't particularly care about regions.
+ let trait_ref = self.tcx.erase_regions(self.tcx.erase_late_bound_regions(trait_ref));
+
+ let src_and_dst = rustc_transmute::Types {
+ dst: trait_ref.substs.type_at(0),
+ src: trait_ref.substs.type_at(1),
+ };
+ let scope = trait_ref.substs.type_at(2);
let Some(assume) =
- rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.skip_binder().substs.const_at(3)) else {
+ rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, trait_ref.substs.const_at(3)) else {
span_bug!(span, "Unable to construct rustc_transmute::Assume where it was previously possible");
};
match rustc_transmute::TransmuteTypeEnv::new(self.infcx).is_transmutable(
@@ -2942,24 +2758,27 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
assume,
) {
rustc_transmute::Answer::No(reason) => {
- let dst = trait_ref.skip_binder().substs.type_at(0);
- let src = trait_ref.skip_binder().substs.type_at(1);
- let custom_err_msg = format!("`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`").to_string();
+ let dst = trait_ref.substs.type_at(0);
+ let src = trait_ref.substs.type_at(1);
+ let custom_err_msg = format!(
+ "`{src}` cannot be safely transmuted into `{dst}` in the defining scope of `{scope}`"
+ );
let reason_msg = match reason {
rustc_transmute::Reason::SrcIsUnspecified => {
- format!("`{src}` does not have a well-specified layout").to_string()
+ format!("`{src}` does not have a well-specified layout")
}
+
rustc_transmute::Reason::DstIsUnspecified => {
- format!("`{dst}` does not have a well-specified layout").to_string()
+ format!("`{dst}` does not have a well-specified layout")
}
+
rustc_transmute::Reason::DstIsBitIncompatible => {
format!("At least one value of `{src}` isn't a bit-valid value of `{dst}`")
- .to_string()
}
+
rustc_transmute::Reason::DstIsPrivate => format!(
"`{dst}` is or contains a type or field that is not visible in that scope"
- )
- .to_string(),
+ ),
// FIXME(bryangarza): Include the number of bytes of src and dst
rustc_transmute::Reason::DstIsTooBig => {
format!("The size of `{src}` is smaller than the size of `{dst}`")
@@ -2975,8 +2794,449 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => span_bug!(span, "Unsupported rustc_transmute::Reason variant"),
}
}
+
+ fn add_tuple_trait_message(
+ &self,
+ obligation_cause_code: &ObligationCauseCode<'tcx>,
+ err: &mut Diagnostic,
+ ) {
+ match obligation_cause_code {
+ ObligationCauseCode::RustCall => {
+ err.set_primary_message("functions with the \"rust-call\" ABI must take a single non-self tuple argument");
+ }
+ ObligationCauseCode::BindingObligation(def_id, _)
+ | ObligationCauseCode::ItemObligation(def_id)
+ if self.tcx.is_fn_trait(*def_id) =>
+ {
+ err.code(rustc_errors::error_code!(E0059));
+ err.set_primary_message(format!(
+ "type parameter to bare `{}` trait must be a tuple",
+ self.tcx.def_path_str(*def_id)
+ ));
+ }
+ _ => {}
+ }
+ }
+
+ fn try_to_add_help_message(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ is_fn_trait: bool,
+ suggested: bool,
+ unsatisfied_const: bool,
+ ) {
+ let body_def_id = obligation.cause.body_id;
+ // Try to report a help message
+ if is_fn_trait
+ && let Ok((implemented_kind, params)) = self.type_implements_fn_trait(
+ obligation.param_env,
+ trait_ref.self_ty(),
+ trait_predicate.skip_binder().constness,
+ trait_predicate.skip_binder().polarity,
+ )
+ {
+ self.add_help_message_for_fn_trait(trait_ref, err, implemented_kind, params);
+ } else if !trait_ref.has_non_region_infer()
+ && self.predicate_can_apply(obligation.param_env, *trait_predicate)
+ {
+ // If a where-clause may be useful, remind the
+ // user that they can add it.
+ //
+ // don't display an on-unimplemented note, as
+ // these notes will often be of the form
+ // "the type `T` can't be frobnicated"
+ // which is somewhat confusing.
+ self.suggest_restricting_param_bound(
+ err,
+ *trait_predicate,
+ None,
+ obligation.cause.body_id,
+ );
+ } else if !suggested && !unsatisfied_const {
+ // Can't show anything else useful, try to find similar impls.
+ let impl_candidates = self.find_similar_impl_candidates(*trait_predicate);
+ if !self.report_similar_impl_candidates(
+ &impl_candidates,
+ trait_ref,
+ body_def_id,
+ err,
+ true,
+ ) {
+ self.report_similar_impl_candidates_for_root_obligation(&obligation, *trait_predicate, body_def_id, err);
+ }
+
+ self.maybe_suggest_convert_to_slice(
+ err,
+ trait_ref,
+ impl_candidates.as_slice(),
+ span,
+ );
+ }
+ }
+
+ fn add_help_message_for_fn_trait(
+ &self,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ err: &mut Diagnostic,
+ implemented_kind: ty::ClosureKind,
+ params: ty::Binder<'tcx, Ty<'tcx>>,
+ ) {
+ // If the type implements `Fn`, `FnMut`, or `FnOnce`, suppress the following
+ // suggestion to add trait bounds for the type, since we only typically implement
+ // these traits once.
+
+ // Note if the `FnMut` or `FnOnce` is less general than the trait we're trying
+ // to implement.
+ let selected_kind = self
+ .tcx
+ .fn_trait_kind_from_def_id(trait_ref.def_id())
+ .expect("expected to map DefId to ClosureKind");
+ if !implemented_kind.extends(selected_kind) {
+ err.note(format!(
+ "`{}` implements `{}`, but it must implement `{}`, which is more general",
+ trait_ref.skip_binder().self_ty(),
+ implemented_kind,
+ selected_kind
+ ));
+ }
+
+ // Note any argument mismatches
+ let given_ty = params.skip_binder();
+ let expected_ty = trait_ref.skip_binder().substs.type_at(1);
+ if let ty::Tuple(given) = given_ty.kind()
+ && let ty::Tuple(expected) = expected_ty.kind()
+ {
+ if expected.len() != given.len() {
+ // Note number of types that were expected and given
+ err.note(
+ format!(
+ "expected a closure taking {} argument{}, but one taking {} argument{} was given",
+ given.len(),
+ pluralize!(given.len()),
+ expected.len(),
+ pluralize!(expected.len()),
+ )
+ );
+ } else if !self.same_type_modulo_infer(given_ty, expected_ty) {
+ // Print type mismatch
+ let (expected_args, given_args) =
+ self.cmp(given_ty, expected_ty);
+ err.note_expected_found(
+ &"a closure with arguments",
+ expected_args,
+ &"a closure with arguments",
+ given_args,
+ );
+ }
+ }
+ }
+
+ fn maybe_add_note_for_unsatisfied_const(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ err: &mut Diagnostic,
+ span: Span,
+ ) -> UnsatisfiedConst {
+ let mut unsatisfied_const = UnsatisfiedConst(false);
+ if trait_predicate.is_const_if_const() && obligation.param_env.is_const() {
+ let non_const_predicate = trait_ref.without_const();
+ let non_const_obligation = Obligation {
+ cause: obligation.cause.clone(),
+ param_env: obligation.param_env.without_const(),
+ predicate: non_const_predicate.to_predicate(self.tcx),
+ recursion_depth: obligation.recursion_depth,
+ };
+ if self.predicate_may_hold(&non_const_obligation) {
+ unsatisfied_const = UnsatisfiedConst(true);
+ err.span_note(
+ span,
+ format!(
+ "the trait `{}` is implemented for `{}`, \
+ but that implementation is not `const`",
+ non_const_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ );
+ }
+ }
+ unsatisfied_const
+ }
+
+ fn report_closure_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ closure_def_id: DefId,
+ found_kind: ty::ClosureKind,
+ kind: ty::ClosureKind,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let closure_span = self.tcx.def_span(closure_def_id);
+ let mut err = struct_span_err!(
+ self.tcx.sess,
+ closure_span,
+ E0525,
+ "expected a closure that implements the `{}` trait, \
+ but this closure only implements `{}`",
+ kind,
+ found_kind
+ );
+
+ err.span_label(
+ closure_span,
+ format!("this closure implements `{}`, not `{}`", found_kind, kind),
+ );
+ err.span_label(
+ obligation.cause.span,
+ format!("the requirement to implement `{}` derives from here", kind),
+ );
+
+ // Additional context information explaining why the closure only implements
+ // a particular trait.
+ if let Some(typeck_results) = &self.typeck_results {
+ let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local());
+ match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) {
+ (ty::ClosureKind::FnOnce, Some((span, place))) => {
+ err.span_label(
+ *span,
+ format!(
+ "closure is `FnOnce` because it moves the \
+ variable `{}` out of its environment",
+ ty::place_to_string_for_capture(self.tcx, place)
+ ),
+ );
+ }
+ (ty::ClosureKind::FnMut, Some((span, place))) => {
+ err.span_label(
+ *span,
+ format!(
+ "closure is `FnMut` because it mutates the \
+ variable `{}` here",
+ ty::place_to_string_for_capture(self.tcx, place)
+ ),
+ );
+ }
+ _ => {}
+ }
+ }
+
+ err
+ }
+
+ fn report_type_parameter_mismatch_cyclic_type_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ terr: TypeError<'tcx>,
+ ) -> DiagnosticBuilder<'tcx, ErrorGuaranteed> {
+ let self_ty = found_trait_ref.self_ty().skip_binder();
+ let (cause, terr) = if let ty::Closure(def_id, _) = self_ty.kind() {
+ (
+ ObligationCause::dummy_with_span(self.tcx.def_span(def_id)),
+ TypeError::CyclicTy(self_ty),
+ )
+ } else {
+ (obligation.cause.clone(), terr)
+ };
+ self.report_and_explain_type_error(
+ TypeTrace::poly_trait_refs(&cause, true, expected_trait_ref, found_trait_ref),
+ terr,
+ )
+ }
+
+ fn report_type_parameter_mismatch_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ found_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ expected_trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+ let found_trait_ref = self.resolve_vars_if_possible(found_trait_ref);
+ let expected_trait_ref = self.resolve_vars_if_possible(expected_trait_ref);
+
+ if expected_trait_ref.self_ty().references_error() {
+ return None;
+ }
+
+ let Some(found_trait_ty) = found_trait_ref.self_ty().no_bound_vars() else {
+ return None;
+ };
+
+ let found_did = match *found_trait_ty.kind() {
+ ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) | ty::Generator(did, ..) => {
+ Some(did)
+ }
+ ty::Adt(def, _) => Some(def.did()),
+ _ => None,
+ };
+
+ let found_node = found_did.and_then(|did| self.tcx.hir().get_if_local(did));
+ let found_span = found_did.and_then(|did| self.tcx.hir().span_if_local(did));
+
+ if self.reported_closure_mismatch.borrow().contains(&(span, found_span)) {
+ // We check closures twice, with obligations flowing in different directions,
+ // but we want to complain about them only once.
+ return None;
+ }
+
+ self.reported_closure_mismatch.borrow_mut().insert((span, found_span));
+
+ let mut not_tupled = false;
+
+ let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() {
+ ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()],
+ _ => {
+ not_tupled = true;
+ vec![ArgKind::empty()]
+ }
+ };
+
+ let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1);
+ let expected = match expected_ty.kind() {
+ ty::Tuple(ref tys) => {
+ tys.iter().map(|t| ArgKind::from_expected_ty(t, Some(span))).collect()
+ }
+ _ => {
+ not_tupled = true;
+ vec![ArgKind::Arg("_".to_owned(), expected_ty.to_string())]
+ }
+ };
+
+ // If this is a `Fn` family trait and either the expected or found
+ // is not tupled, then fall back to just a regular mismatch error.
+ // This shouldn't be common unless manually implementing one of the
+ // traits manually, but don't make it more confusing when it does
+ // happen.
+ Some(
+ if Some(expected_trait_ref.def_id()) != self.tcx.lang_items().gen_trait() && not_tupled
+ {
+ self.report_and_explain_type_error(
+ TypeTrace::poly_trait_refs(
+ &obligation.cause,
+ true,
+ expected_trait_ref,
+ found_trait_ref,
+ ),
+ ty::error::TypeError::Mismatch,
+ )
+ } else if found.len() == expected.len() {
+ self.report_closure_arg_mismatch(
+ span,
+ found_span,
+ found_trait_ref,
+ expected_trait_ref,
+ obligation.cause.code(),
+ found_node,
+ obligation.param_env,
+ )
+ } else {
+ let (closure_span, closure_arg_span, found) = found_did
+ .and_then(|did| {
+ let node = self.tcx.hir().get_if_local(did)?;
+ let (found_span, closure_arg_span, found) =
+ self.get_fn_like_arguments(node)?;
+ Some((Some(found_span), closure_arg_span, found))
+ })
+ .unwrap_or((found_span, None, found));
+
+ self.report_arg_count_mismatch(
+ span,
+ closure_span,
+ expected,
+ found,
+ found_trait_ty.is_closure(),
+ closure_arg_span,
+ )
+ },
+ )
+ }
+
+ fn report_not_const_evaluatable_error(
+ &self,
+ obligation: &PredicateObligation<'tcx>,
+ span: Span,
+ ) -> Option<DiagnosticBuilder<'tcx, ErrorGuaranteed>> {
+ if !self.tcx.features().generic_const_exprs {
+ let mut err = self
+ .tcx
+ .sess
+ .struct_span_err(span, "constant expression depends on a generic parameter");
+ // FIXME(const_generics): we should suggest to the user how they can resolve this
+ // issue. However, this is currently not actually possible
+ // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083).
+ //
+ // Note that with `feature(generic_const_exprs)` this case should not
+ // be reachable.
+ err.note("this may fail depending on what value the parameter takes");
+ err.emit();
+ return None;
+ }
+
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::ConstEvaluatable(ct) => {
+ let ty::ConstKind::Unevaluated(uv) = ct.kind() else {
+ bug!("const evaluatable failed for non-unevaluated const `{ct:?}`");
+ };
+ let mut err = self.tcx.sess.struct_span_err(span, "unconstrained generic constant");
+ let const_span = self.tcx.def_span(uv.def);
+ match self.tcx.sess.source_map().span_to_snippet(const_span) {
+ Ok(snippet) => err.help(format!(
+ "try adding a `where` bound using this expression: `where [(); {}]:`",
+ snippet
+ )),
+ _ => err.help("consider adding a `where` bound using this expression"),
+ };
+ Some(err)
+ }
+ _ => {
+ span_bug!(
+ span,
+ "unexpected non-ConstEvaluatable predicate, this should not be reachable"
+ )
+ }
+ }
+ }
}
+struct UnsatisfiedConst(pub bool);
+
+fn get_explanation_based_on_obligation<'tcx>(
+ obligation: &PredicateObligation<'tcx>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
+ trait_predicate: &ty::PolyTraitPredicate<'tcx>,
+ pre_message: String,
+) -> String {
+ if let ObligationCauseCode::MainFunctionType = obligation.cause.code() {
+ "consider using `()`, or a `Result`".to_owned()
+ } else {
+ let ty_desc = match trait_ref.skip_binder().self_ty().kind() {
+ ty::FnDef(_, _) => Some("fn item"),
+ ty::Closure(_, _) => Some("closure"),
+ _ => None,
+ };
+
+ match ty_desc {
+ Some(desc) => format!(
+ "{}the trait `{}` is not implemented for {} `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ desc,
+ trait_ref.skip_binder().self_ty(),
+ ),
+ None => format!(
+ "{}the trait `{}` is not implemented for `{}`",
+ pre_message,
+ trait_predicate.print_modifiers_and_trait_path(),
+ trait_ref.skip_binder().self_ty(),
+ ),
+ }
+ }
+}
/// Crude way of getting back an `Expr` from a `Span`.
pub struct FindExprBySpan<'hir> {
pub span: Span,
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
index a9c4e1268..10bd027b6 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs
@@ -306,6 +306,14 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
}
+
+ // `&[{integral}]` - `FromIterator` needs that.
+ if let ty::Ref(_, ref_ty, rustc_ast::Mutability::Not) = self_ty.kind()
+ && let ty::Slice(sty) = ref_ty.kind()
+ && sty.is_integral()
+ {
+ flags.push((sym::_Self, Some("&[{integral}]".to_owned())));
+ }
});
if let Ok(Some(command)) = OnUnimplementedDirective::of_item(self.tcx, def_id) {
@@ -327,7 +335,7 @@ pub struct OnUnimplementedDirective {
pub label: Option<OnUnimplementedFormatString>,
pub note: Option<OnUnimplementedFormatString>,
pub parent_label: Option<OnUnimplementedFormatString>,
- pub append_const_msg: Option<Option<Symbol>>,
+ pub append_const_msg: Option<AppendConstMessage>,
}
/// For the `#[rustc_on_unimplemented]` attribute
@@ -337,11 +345,21 @@ pub struct OnUnimplementedNote {
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>>,
+ // If none, should fall back to a generic message
+ pub append_const_msg: Option<AppendConstMessage>,
+}
+
+/// Append a message for `~const Trait` errors.
+#[derive(Clone, Copy, PartialEq, Eq, Debug)]
+pub enum AppendConstMessage {
+ Default,
+ Custom(Symbol),
+}
+
+impl Default for AppendConstMessage {
+ fn default() -> Self {
+ AppendConstMessage::Default
+ }
}
impl<'tcx> OnUnimplementedDirective {
@@ -419,10 +437,10 @@ impl<'tcx> OnUnimplementedDirective {
}
} 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));
+ append_const_msg = Some(AppendConstMessage::Custom(msg));
continue;
} else if item.is_word() {
- append_const_msg = Some(None);
+ append_const_msg = Some(AppendConstMessage::Default);
continue;
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
index fb75ec767..82bad96ea 100644
--- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
+++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs
@@ -25,23 +25,22 @@ use rustc_hir::{AsyncGeneratorKind, GeneratorKind, Node};
use rustc_hir::{Expr, HirId};
use rustc_infer::infer::error_reporting::TypeErrCtxt;
use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
-use rustc_infer::infer::{InferOk, LateBoundRegionConversionTime};
+use rustc_infer::infer::{DefineOpaqueTypes, InferOk, LateBoundRegionConversionTime};
use rustc_middle::hir::map;
use rustc_middle::ty::error::TypeError::{self, Sorts};
-use rustc_middle::ty::relate::TypeRelation;
use rustc_middle::ty::{
self, suggest_arbitrary_trait_bound, suggest_constraining_type_param, AdtKind,
- GeneratorDiagnosticData, GeneratorInteriorTypeCause, Infer, InferTy, InternalSubsts,
- IsSuggestable, ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder,
- TypeSuperFoldable, TypeVisitableExt, TypeckResults,
+ GeneratorDiagnosticData, GeneratorInteriorTypeCause, InferTy, InternalSubsts, IsSuggestable,
+ ToPredicate, Ty, TyCtxt, TypeAndMut, TypeFoldable, TypeFolder, TypeSuperFoldable,
+ TypeVisitableExt, TypeckResults,
};
use rustc_span::def_id::LocalDefId;
use rustc_span::symbol::{sym, Ident, Symbol};
use rustc_span::{BytePos, DesugaringKind, ExpnKind, MacroKind, Span, DUMMY_SP};
use rustc_target::spec::abi;
+use std::iter;
use std::ops::Deref;
-use super::method_chain::CollectAllMismatches;
use super::InferCtxtPrivExt;
use crate::infer::InferCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
@@ -262,7 +261,6 @@ pub trait TypeErrCtxtExt<'tcx> {
fn suggest_impl_trait(
&self,
err: &mut Diagnostic,
- span: Span,
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool;
@@ -319,6 +317,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn note_obligation_cause_code<T>(
&self,
+ body_id: LocalDefId,
err: &mut Diagnostic,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
@@ -359,8 +358,9 @@ pub trait TypeErrCtxtExt<'tcx> {
);
fn note_function_argument_obligation(
&self,
- arg_hir_id: HirId,
+ body_id: LocalDefId,
err: &mut Diagnostic,
+ arg_hir_id: HirId,
parent_code: &ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
predicate: ty::Predicate<'tcx>,
@@ -386,7 +386,7 @@ pub trait TypeErrCtxtExt<'tcx> {
fn maybe_suggest_convert_to_slice(
&self,
err: &mut Diagnostic,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
);
@@ -420,7 +420,7 @@ fn suggest_restriction<'tcx>(
) {
if hir_generics.where_clause_span.from_expansion()
|| hir_generics.where_clause_span.desugaring_kind().is_some()
- || projection.map_or(false, |projection| tcx.opt_rpitit_info(projection.def_id).is_some())
+ || projection.is_some_and(|projection| tcx.opt_rpitit_info(projection.def_id).is_some())
{
return;
}
@@ -515,7 +515,7 @@ fn suggest_restriction<'tcx>(
err.span_suggestion_verbose(
sp,
- &format!("consider further restricting {}", msg),
+ format!("consider further restricting {}", msg),
suggestion,
Applicability::MachineApplicable,
);
@@ -530,6 +530,10 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
associated_ty: Option<(&'static str, Ty<'tcx>)>,
mut body_id: LocalDefId,
) {
+ if trait_pred.skip_binder().polarity == ty::ImplPolarity::Negative {
+ return;
+ }
+
let trait_pred = self.resolve_numeric_literals_with_default(trait_pred);
let self_ty = trait_pred.skip_binder().self_ty();
@@ -964,7 +968,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// a more general note.
err.span_suggestion_verbose(
obligation.cause.span.shrink_to_hi(),
- &msg,
+ msg,
format!("({args})"),
Applicability::HasPlaceholders,
);
@@ -994,7 +998,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
_ => return false,
};
- err.help(&format!("{msg}: `{name}({args})`"));
+ err.help(format!("{msg}: `{name}({args})`"));
}
true
}
@@ -1334,7 +1338,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let msg = format!("the trait bound `{}` is not satisfied", old_pred);
if has_custom_message {
- err.note(&msg);
+ err.note(msg);
} else {
err.message =
vec![(rustc_errors::DiagnosticMessage::Str(msg), Style::NoStyle)];
@@ -1358,7 +1362,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
let is_mut = mut_ref_self_ty_satisfies_pred || ref_inner_ty_mut;
let sugg_prefix = format!("&{}", if is_mut { "mut " } else { "" });
- let sugg_msg = &format!(
+ let sugg_msg = format!(
"consider{} borrowing here",
if is_mut { " mutably" } else { "" }
);
@@ -1381,7 +1385,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
}
- // Issue #104961, we need to add parentheses properly for compond expressions
+ // Issue #104961, we need to add parentheses properly for compound expressions
// for example, `x.starts_with("hi".to_string() + "you")`
// should be `x.starts_with(&("hi".to_string() + "you"))`
let Some(body_id) = self.tcx.hir().maybe_body_owned_by(obligation.cause.body_id) else { return false; };
@@ -1437,8 +1441,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err: &mut Diagnostic,
obligation: &PredicateObligation<'tcx>,
self_ty: Ty<'tcx>,
- object_ty: Ty<'tcx>,
+ target_ty: Ty<'tcx>,
) {
+ let ty::Ref(_, object_ty, hir::Mutability::Not) = target_ty.kind() else { return; };
let ty::Dynamic(predicates, _, ty::Dyn) = object_ty.kind() else { return; };
let self_ref_ty = self.tcx.mk_imm_ref(self.tcx.lifetimes.re_erased, self_ty);
@@ -1452,8 +1457,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.span_suggestion(
obligation.cause.span.shrink_to_lo(),
- &format!(
- "consider borrowing the value, since `&{self_ty}` can be coerced into `{object_ty}`"
+ format!(
+ "consider borrowing the value, since `&{self_ty}` can be coerced into `{target_ty}`"
),
"&",
Applicability::MaybeIncorrect,
@@ -1505,7 +1510,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
};
err.multipart_suggestion_verbose(
- &msg,
+ msg,
suggestions,
Applicability::MachineApplicable,
);
@@ -1583,55 +1588,68 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) {
- let span = obligation.cause.span;
-
- if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() {
- let hir = self.tcx.hir();
- if let Some(hir::Node::Expr(expr)) = hir_id.and_then(|hir_id| hir.find(hir_id)) {
- // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
- // and if not maybe suggest doing something else? If we kept the expression around we
- // could also check if it is an fn call (very likely) and suggest changing *that*, if
- // it is from the local crate.
+ let hir = self.tcx.hir();
+ if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = obligation.cause.code().peel_derives()
+ && let hir::Node::Expr(expr) = hir.get(*hir_id)
+ {
+ // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()`
+ // and if not maybe suggest doing something else? If we kept the expression around we
+ // could also check if it is an fn call (very likely) and suggest changing *that*, if
+ // it is from the local crate.
+
+ // use nth(1) to skip one layer of desugaring from `IntoIter::into_iter`
+ if let Some((_, hir::Node::Expr(await_expr))) = hir.parent_iter(*hir_id).nth(1)
+ && let Some(expr_span) = expr.span.find_ancestor_inside(await_expr.span)
+ {
+ let removal_span = self.tcx
+ .sess
+ .source_map()
+ .span_extend_while(expr_span, char::is_whitespace)
+ .unwrap_or(expr_span)
+ .shrink_to_hi()
+ .to(await_expr.span.shrink_to_hi());
err.span_suggestion(
- span,
+ removal_span,
"remove the `.await`",
"",
Applicability::MachineApplicable,
);
- // FIXME: account for associated `async fn`s.
- if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
- if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
- obligation.predicate.kind().skip_binder()
+ } else {
+ err.span_label(obligation.cause.span, "remove the `.await`");
+ }
+ // FIXME: account for associated `async fn`s.
+ if let hir::Expr { span, kind: hir::ExprKind::Call(base, _), .. } = expr {
+ if let ty::PredicateKind::Clause(ty::Clause::Trait(pred)) =
+ obligation.predicate.kind().skip_binder()
+ {
+ err.span_label(*span, format!("this call returns `{}`", pred.self_ty()));
+ }
+ if let Some(typeck_results) = &self.typeck_results
+ && let ty = typeck_results.expr_ty_adjusted(base)
+ && let ty::FnDef(def_id, _substs) = ty.kind()
+ && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
+ hir.get_if_local(*def_id)
{
- err.span_label(*span, &format!("this call returns `{}`", pred.self_ty()));
- }
- if let Some(typeck_results) = &self.typeck_results
- && let ty = typeck_results.expr_ty_adjusted(base)
- && let ty::FnDef(def_id, _substs) = ty.kind()
- && let Some(hir::Node::Item(hir::Item { ident, span, vis_span, .. })) =
- hir.get_if_local(*def_id)
- {
- let msg = format!(
- "alternatively, consider making `fn {}` asynchronous",
- ident
+ let msg = format!(
+ "alternatively, consider making `fn {}` asynchronous",
+ ident
+ );
+ if vis_span.is_empty() {
+ err.span_suggestion_verbose(
+ span.shrink_to_lo(),
+ msg,
+ "async ",
+ Applicability::MaybeIncorrect,
+ );
+ } else {
+ err.span_suggestion_verbose(
+ vis_span.shrink_to_hi(),
+ msg,
+ " async",
+ Applicability::MaybeIncorrect,
);
- if vis_span.is_empty() {
- err.span_suggestion_verbose(
- span.shrink_to_lo(),
- &msg,
- "async ",
- Applicability::MaybeIncorrect,
- );
- } else {
- err.span_suggestion_verbose(
- vis_span.shrink_to_hi(),
- &msg,
- " async",
- Applicability::MaybeIncorrect,
- );
- }
}
- }
+ }
}
}
}
@@ -1704,7 +1722,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
Applicability::MachineApplicable,
);
} else {
- err.note(&format!(
+ err.note(format!(
"`{}` is implemented for `{:?}`, but not for `{:?}`",
trait_pred.print_modifiers_and_trait_path(),
suggested_ty,
@@ -1741,7 +1759,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
err.span_label(
expr.span,
- &format!(
+ format!(
"this expression has type `{}`, which implements `{}`",
ty,
trait_pred.print_modifiers_and_trait_path()
@@ -1773,215 +1791,66 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn suggest_impl_trait(
&self,
err: &mut Diagnostic,
- span: Span,
obligation: &PredicateObligation<'tcx>,
trait_pred: ty::PolyTraitPredicate<'tcx>,
) -> bool {
- match obligation.cause.code().peel_derives() {
- // Only suggest `impl Trait` if the return type is unsized because it is `dyn Trait`.
- ObligationCauseCode::SizedReturnType => {}
- _ => return false,
- }
-
- let hir = self.tcx.hir();
- let fn_hir_id = hir.local_def_id_to_hir_id(obligation.cause.body_id);
- let node = hir.find_by_def_id(obligation.cause.body_id);
- let Some(hir::Node::Item(hir::Item {
- kind: hir::ItemKind::Fn(sig, _, body_id),
- ..
- })) = node
- else {
+ let ObligationCauseCode::SizedReturnType = obligation.cause.code() else {
return false;
};
- let body = hir.body(*body_id);
- let trait_pred = self.resolve_vars_if_possible(trait_pred);
- let ty = trait_pred.skip_binder().self_ty();
- let is_object_safe = match ty.kind() {
- ty::Dynamic(predicates, _, ty::Dyn) => {
- // If the `dyn Trait` is not object safe, do not suggest `Box<dyn Trait>`.
- predicates
- .principal_def_id()
- .map_or(true, |def_id| self.tcx.check_is_object_safe(def_id))
- }
- // We only want to suggest `impl Trait` to `dyn Trait`s.
- // For example, `fn foo() -> str` needs to be filtered out.
- _ => return false,
- };
-
- let hir::FnRetTy::Return(ret_ty) = sig.decl.output else {
+ let ty::Dynamic(_, _, ty::Dyn) = trait_pred.self_ty().skip_binder().kind() else {
return false;
};
- // Use `TypeVisitor` instead of the output type directly to find the span of `ty` for
- // cases like `fn foo() -> (dyn Trait, i32) {}`.
- // Recursively look for `TraitObject` types and if there's only one, use that span to
- // suggest `impl Trait`.
-
- // Visit to make sure there's a single `return` type to suggest `impl Trait`,
- // otherwise suggest using `Box<dyn Trait>` or an enum.
- let mut visitor = ReturnsVisitor::default();
- visitor.visit_body(&body);
-
- let typeck_results = self.typeck_results.as_ref().unwrap();
- let Some(liberated_sig) = typeck_results.liberated_fn_sigs().get(fn_hir_id).copied() else { return false; };
-
- let ret_types = visitor
- .returns
- .iter()
- .filter_map(|expr| Some((expr.span, typeck_results.node_type_opt(expr.hir_id)?)))
- .map(|(expr_span, ty)| (expr_span, self.resolve_vars_if_possible(ty)));
- let (last_ty, all_returns_have_same_type, only_never_return) = ret_types.clone().fold(
- (None, true, true),
- |(last_ty, mut same, only_never_return): (std::option::Option<Ty<'_>>, bool, bool),
- (_, ty)| {
- let ty = self.resolve_vars_if_possible(ty);
- same &=
- !matches!(ty.kind(), ty::Error(_))
- && last_ty.map_or(true, |last_ty| {
- // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes
- // *after* in the dependency graph.
- match (ty.kind(), last_ty.kind()) {
- (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_)))
- | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_)))
- | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_)))
- | (
- Infer(InferTy::FreshFloatTy(_)),
- Infer(InferTy::FreshFloatTy(_)),
- ) => true,
- _ => ty == last_ty,
- }
- });
- (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never))
- },
- );
- let mut spans_and_needs_box = vec![];
-
- match liberated_sig.output().kind() {
- ty::Dynamic(predicates, _, ty::Dyn) => {
- let cause = ObligationCause::misc(ret_ty.span, obligation.cause.body_id);
- let param_env = ty::ParamEnv::empty();
-
- if !only_never_return {
- for (expr_span, return_ty) in ret_types {
- let self_ty_satisfies_dyn_predicates = |self_ty| {
- predicates.iter().all(|predicate| {
- let pred = predicate.with_self_ty(self.tcx, self_ty);
- let obl = Obligation::new(self.tcx, cause.clone(), param_env, pred);
- self.predicate_may_hold(&obl)
- })
- };
-
- if let ty::Adt(def, substs) = return_ty.kind()
- && def.is_box()
- && self_ty_satisfies_dyn_predicates(substs.type_at(0))
- {
- spans_and_needs_box.push((expr_span, false));
- } else if self_ty_satisfies_dyn_predicates(return_ty) {
- spans_and_needs_box.push((expr_span, true));
- } else {
- return false;
- }
- }
- }
- }
- _ => return false,
- };
-
- let sm = self.tcx.sess.source_map();
- if !ret_ty.span.overlaps(span) {
- return false;
- }
- let snippet = if let hir::TyKind::TraitObject(..) = ret_ty.kind {
- if let Ok(snippet) = sm.span_to_snippet(ret_ty.span) {
- snippet
- } else {
- return false;
- }
- } else {
- // Substitute the type, so we can print a fixup given `type Alias = dyn Trait`
- let name = liberated_sig.output().to_string();
- let name =
- name.strip_prefix('(').and_then(|name| name.strip_suffix(')')).unwrap_or(&name);
- if !name.starts_with("dyn ") {
- return false;
- }
- name.to_owned()
- };
-
err.code(error_code!(E0746));
err.set_primary_message("return type cannot have an unboxed trait object");
err.children.clear();
- let impl_trait_msg = "for information on `impl Trait`, see \
- <https://doc.rust-lang.org/book/ch10-02-traits.html\
- #returning-types-that-implement-traits>";
- let trait_obj_msg = "for information on trait objects, see \
- <https://doc.rust-lang.org/book/ch17-02-trait-objects.html\
- #using-trait-objects-that-allow-for-values-of-different-types>";
-
- let has_dyn = snippet.split_whitespace().next().map_or(false, |s| s == "dyn");
- let trait_obj = if has_dyn { &snippet[4..] } else { &snippet };
- if only_never_return {
- // No return paths, probably using `panic!()` or similar.
- // Suggest `-> impl Trait`, and if `Trait` is object safe, `-> Box<dyn Trait>`.
- suggest_trait_object_return_type_alternatives(
- err,
- ret_ty.span,
- trait_obj,
- is_object_safe,
- );
- } else if let (Some(last_ty), true) = (last_ty, all_returns_have_same_type) {
- // Suggest `-> impl Trait`.
+
+ let span = obligation.cause.span;
+ if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span)
+ && snip.starts_with("dyn ")
+ {
err.span_suggestion(
- ret_ty.span,
- &format!(
- "use `impl {1}` as the return type, as all return paths are of type `{}`, \
- which implements `{1}`",
- last_ty, trait_obj,
- ),
- format!("impl {}", trait_obj),
- Applicability::MachineApplicable,
+ span.with_hi(span.lo() + BytePos(4)),
+ "return an `impl Trait` instead of a `dyn Trait`, \
+ if all returned values are the same type",
+ "impl ",
+ Applicability::MaybeIncorrect,
);
- err.note(impl_trait_msg);
- } else {
- if is_object_safe {
- // Suggest `-> Box<dyn Trait>` and `Box::new(returned_value)`.
- err.multipart_suggestion(
- "return a boxed trait object instead",
- vec![
- (ret_ty.span.shrink_to_lo(), "Box<".to_string()),
- (span.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- for (span, needs_box) in spans_and_needs_box {
- if needs_box {
- err.multipart_suggestion(
- "... and box this value",
- vec![
- (span.shrink_to_lo(), "Box::new(".to_string()),
- (span.shrink_to_hi(), ")".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- }
- }
+ }
+
+ let body = self.tcx.hir().body(self.tcx.hir().body_owned_by(obligation.cause.body_id));
+
+ let mut visitor = ReturnsVisitor::default();
+ visitor.visit_body(&body);
+
+ let mut sugg =
+ vec![(span.shrink_to_lo(), "Box<".to_string()), (span.shrink_to_hi(), ">".to_string())];
+ sugg.extend(visitor.returns.into_iter().flat_map(|expr| {
+ let span = expr.span.find_ancestor_in_same_ctxt(obligation.cause.span).unwrap_or(expr.span);
+ if !span.can_be_used_for_suggestions() {
+ vec![]
+ } else if let hir::ExprKind::Call(path, ..) = expr.kind
+ && let hir::ExprKind::Path(hir::QPath::TypeRelative(ty, method)) = path.kind
+ && method.ident.name == sym::new
+ && let hir::TyKind::Path(hir::QPath::Resolved(.., box_path)) = ty.kind
+ && box_path.res.opt_def_id().is_some_and(|def_id| Some(def_id) == self.tcx.lang_items().owned_box())
+ {
+ // Don't box `Box::new`
+ vec![]
} else {
- // This is currently not possible to trigger because E0038 takes precedence, but
- // leave it in for completeness in case anything changes in an earlier stage.
- err.note(&format!(
- "if trait `{}` were object-safe, you could return a trait object",
- trait_obj,
- ));
+ vec![
+ (span.shrink_to_lo(), "Box::new(".to_string()),
+ (span.shrink_to_hi(), ")".to_string()),
+ ]
}
- err.note(trait_obj_msg);
- err.note(&format!(
- "if all the returned values were of the same type you could use `impl {}` as the \
- return type",
- trait_obj,
- ));
- err.note(impl_trait_msg);
- err.note("you can create a new `enum` with a variant for each returned type");
- }
+ }));
+
+ err.multipart_suggestion(
+ "box the return type, and wrap all of the returned values in `Box::new`",
+ sugg,
+ Applicability::MaybeIncorrect,
+ );
+
true
}
@@ -2014,7 +1883,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
err.span_label(
expr.span,
- &format!("this returned value is of type `{}`", ty),
+ format!("this returned value is of type `{}`", ty),
);
}
}
@@ -2164,7 +2033,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
) {
if let Some(assoc_item) = self.tcx.opt_associated_item(item_def_id) {
if let ty::AssocKind::Const | ty::AssocKind::Type = assoc_item.kind {
- err.note(&format!(
+ err.note(format!(
"{}s cannot be accessed directly on a `trait`, they can only be \
accessed through a specific `impl`",
self.tcx.def_kind_descr(assoc_item.kind.as_def_kind(), item_def_id)
@@ -2428,10 +2297,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
&& generator_did.is_local()
// Try to avoid cycles.
&& !generator_within_in_progress_typeck
+ && let Some(generator_info) = self.tcx.mir_generator_witnesses(generator_did)
{
- let generator_info = &self.tcx.mir_generator_witnesses(generator_did);
debug!(?generator_info);
-
'find_source: for (variant, source_info) in
generator_info.variant_fields.iter().zip(&generator_info.variant_source_info)
{
@@ -2594,7 +2462,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
err.span_note(
span,
- &format!(
+ format!(
"{} {} as this value is used across {}",
future_or_generator, trait_explanation, an_await_or_yield
),
@@ -2615,7 +2483,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
err.span_note(
span,
- &format!(
+ format!(
"future {not_trait} as it awaits another future which {not_trait}",
not_trait = trait_explanation
),
@@ -2717,7 +2585,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let mut span = MultiSpan::from_span(upvar_span);
span.push_span_label(upvar_span, span_label);
- err.span_note(span, &span_note);
+ err.span_note(span, span_note);
}
}
@@ -2725,6 +2593,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// bound that introduced the obligation (e.g. `T: Send`).
debug!(?next_code);
self.note_obligation_cause_code(
+ obligation.cause.body_id,
err,
obligation.predicate,
obligation.param_env,
@@ -2736,6 +2605,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn note_obligation_cause_code<T>(
&self,
+ body_id: LocalDefId,
err: &mut Diagnostic,
predicate: T,
param_env: ty::ParamEnv<'tcx>,
@@ -2773,7 +2643,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
| ObligationCauseCode::LetElse
| ObligationCauseCode::BinOp { .. }
| ObligationCauseCode::AscribeUserTypeProvePredicate(..)
- | ObligationCauseCode::RustCall => {}
+ | ObligationCauseCode::RustCall
+ | ObligationCauseCode::DropImpl => {}
ObligationCauseCode::SliceOrArrayElem => {
err.note("slice and array elements must have `Sized` type");
}
@@ -2781,15 +2652,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
err.note("only the last element of a tuple may have a dynamically sized type");
}
ObligationCauseCode::ProjectionWf(data) => {
- err.note(&format!("required so that the projection `{data}` is well-formed"));
+ err.note(format!("required so that the projection `{data}` is well-formed"));
}
ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => {
- err.note(&format!(
+ err.note(format!(
"required so that reference `{ref_ty}` does not outlive its referent"
));
}
ObligationCauseCode::ObjectTypeBound(object_ty, region) => {
- err.note(&format!(
+ err.note(format!(
"required so that the lifetime bound of `{}` for `{}` is satisfied",
region, object_ty,
));
@@ -2825,35 +2696,32 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if span.is_visible(sm) {
let msg = format!("required by this bound in `{short_item_name}`");
multispan.push_span_label(span, msg);
- err.span_note(multispan, &descr);
+ err.span_note(multispan, descr);
} else {
- err.span_note(tcx.def_span(item_def_id), &descr);
+ err.span_note(tcx.def_span(item_def_id), descr);
}
}
- ObligationCauseCode::ObjectCastObligation(concrete_ty, object_ty) => {
- let (concrete_ty, concrete_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(concrete_ty));
- let (object_ty, object_file) =
- self.tcx.short_ty_string(self.resolve_vars_if_possible(object_ty));
- err.note(&with_forced_trimmed_paths!(format!(
- "required for the cast from `{concrete_ty}` to the object type `{object_ty}`",
+ ObligationCauseCode::Coercion { source, target } => {
+ let (source, source_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(source));
+ let (target, target_file) =
+ self.tcx.short_ty_string(self.resolve_vars_if_possible(target));
+ err.note(with_forced_trimmed_paths!(format!(
+ "required for the cast from `{source}` to `{target}`",
)));
- if let Some(file) = concrete_file {
- err.note(&format!(
- "the full name for the casted type has been written to '{}'",
+ if let Some(file) = source_file {
+ err.note(format!(
+ "the full name for the source type has been written to '{}'",
file.display(),
));
}
- if let Some(file) = object_file {
- err.note(&format!(
- "the full name for the object type has been written to '{}'",
+ if let Some(file) = target_file {
+ err.note(format!(
+ "the full name for the target type has been written to '{}'",
file.display(),
));
}
}
- ObligationCauseCode::Coercion { source: _, target } => {
- err.note(&format!("required by cast to type `{}`", self.ty_to_string(target)));
- }
ObligationCauseCode::RepeatElementCopy { is_const_fn } => {
err.note(
"the `Copy` trait is required because this value will be copied for each element of the array",
@@ -3055,8 +2923,8 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
));
match ty.kind() {
ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) {
- Some(ident) => err.span_note(ident.span, &msg),
- None => err.note(&msg),
+ Some(ident) => err.span_note(ident.span, msg),
+ None => err.note(msg),
},
ty::Alias(ty::Opaque, ty::AliasTy { def_id, .. }) => {
// If the previous type is async fn, this is the future generated by the body of an async function.
@@ -3068,7 +2936,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"note_obligation_cause_code: check for async fn"
);
if is_future
- && obligated_types.last().map_or(false, |ty| match ty.kind() {
+ && obligated_types.last().is_some_and(|ty| match ty.kind() {
ty::Generator(last_def_id, ..) => {
tcx.generator_is_async(*last_def_id)
}
@@ -3077,7 +2945,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
break 'print;
}
- err.span_note(self.tcx.def_span(def_id), &msg)
+ err.span_note(self.tcx.def_span(def_id), msg)
}
ty::GeneratorWitness(bound_tys) => {
use std::fmt::Write;
@@ -3113,7 +2981,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
let kind = tcx.generator_kind(def_id).unwrap().descr();
err.span_note(
sp,
- with_forced_trimmed_paths!(&format!(
+ with_forced_trimmed_paths!(format!(
"required because it's used within this {kind}",
)),
)
@@ -3123,7 +2991,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"required because it's used within this closure",
),
ty::Str => err.note("`str` is considered to contain a `[u8]` slice for auto trait purposes"),
- _ => err.note(&msg),
+ _ => err.note(msg),
};
}
}
@@ -3135,6 +3003,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3146,6 +3015,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
} else {
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3177,7 +3047,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// FIXME: we should do something else so that it works even on crate foreign
// auto traits.
is_auto_trait = matches!(is_auto, hir::IsAuto::Yes);
- err.span_note(ident.span, &msg);
+ err.span_note(ident.span, msg);
}
Some(Node::Item(hir::Item {
kind: hir::ItemKind::Impl(hir::Impl { of_trait, self_ty, .. }),
@@ -3206,15 +3076,15 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
"unsatisfied trait bound introduced here",
);
}
- err.span_note(spans, &msg);
+ err.span_note(spans, msg);
}
_ => {
- err.note(&msg);
+ err.note(msg);
}
};
if let Some(file) = file {
- err.note(&format!(
+ err.note(format!(
"the full type name has been written to '{}'",
file.display(),
));
@@ -3254,19 +3124,19 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
parent_trait_pred = child_trait_pred;
}
if count > 0 {
- err.note(&format!(
+ err.note(format!(
"{} redundant requirement{} hidden",
count,
pluralize!(count)
));
let (self_ty, file) =
self.tcx.short_ty_string(parent_trait_pred.skip_binder().self_ty());
- err.note(&format!(
+ err.note(format!(
"required for `{self_ty}` to implement `{}`",
parent_trait_pred.print_modifiers_and_trait_path()
));
if let Some(file) = file {
- err.note(&format!(
+ err.note(format!(
"the full type name has been written to '{}'",
file.display(),
));
@@ -3275,6 +3145,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3290,6 +3161,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// #74711: avoid a stack overflow
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
parent_predicate,
param_env,
@@ -3306,8 +3178,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
..
} => {
self.note_function_argument_obligation(
- arg_hir_id,
+ body_id,
err,
+ arg_hir_id,
parent_code,
param_env,
predicate,
@@ -3315,6 +3188,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
);
ensure_sufficient_stack(|| {
self.note_obligation_cause_code(
+ body_id,
err,
predicate,
param_env,
@@ -3347,7 +3221,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
{
assoc_span.push_span_label(ident.span, "in this trait");
}
- err.span_note(assoc_span, &msg);
+ err.span_note(assoc_span, msg);
}
ObligationCauseCode::TrivialBound => {
err.help("see issue #48214");
@@ -3485,7 +3359,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
_ => None,
};
let trait_pred = trait_pred.map_bound_ref(|tr| ty::TraitPredicate {
- trait_ref: self.tcx.mk_trait_ref(
+ trait_ref: ty::TraitRef::new(self.tcx,
trait_pred.def_id(),
[field_ty].into_iter().chain(trait_substs),
),
@@ -3503,7 +3377,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if can_derive {
err.span_suggestion_verbose(
self.tcx.def_span(adt.did()).shrink_to_lo(),
- &format!(
+ format!(
"consider annotating `{}` with `#[derive({})]`",
trait_pred.skip_binder().self_ty(),
diagnostic_name,
@@ -3536,8 +3410,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
}
fn note_function_argument_obligation(
&self,
- arg_hir_id: HirId,
+ body_id: LocalDefId,
err: &mut Diagnostic,
+ arg_hir_id: HirId,
parent_code: &ObligationCauseCode<'tcx>,
param_env: ty::ParamEnv<'tcx>,
failed_pred: ty::Predicate<'tcx>,
@@ -3570,7 +3445,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
// to an associated type (as seen from `trait_pred`) in the predicate. Like in
// trait_pred `S: Sum<<Self as Iterator>::Item>` and predicate `i32: Sum<&()>`
let mut type_diffs = vec![];
-
if let ObligationCauseCode::ExprBindingObligation(def_id, _, _, idx) = parent_code.deref()
&& let Some(node_substs) = typeck_results.node_substs_opt(call_hir_id)
&& let where_clauses = self.tcx.predicates_of(def_id).instantiate(self.tcx, node_substs)
@@ -3579,14 +3453,26 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
if let Some(where_pred) = where_pred.to_opt_poly_trait_pred()
&& let Some(failed_pred) = failed_pred.to_opt_poly_trait_pred()
{
- let mut c = CollectAllMismatches {
- infcx: self.infcx,
- param_env,
- errors: vec![],
+ let where_pred = self.instantiate_binder_with_placeholders(where_pred);
+ let failed_pred = self.instantiate_binder_with_fresh_vars(
+ expr.span,
+ LateBoundRegionConversionTime::FnCall,
+ failed_pred
+ );
+
+ let zipped =
+ iter::zip(where_pred.trait_ref.substs, failed_pred.trait_ref.substs);
+ for (expected, actual) in zipped {
+ self.probe(|_| {
+ match self
+ .at(&ObligationCause::misc(expr.span, body_id), param_env)
+ .eq(DefineOpaqueTypes::No, expected, actual)
+ {
+ Ok(_) => (), // We ignore nested obligations here for now.
+ Err(err) => type_diffs.push(err),
+ }
+ })
};
- if let Ok(_) = c.relate(where_pred, failed_pred) {
- type_diffs = c.errors;
- }
} else if let Some(where_pred) = where_pred.to_opt_poly_projection_pred()
&& let Some(failed_pred) = failed_pred.to_opt_poly_projection_pred()
&& let Some(found) = failed_pred.skip_binder().term.ty()
@@ -3848,7 +3734,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
fn maybe_suggest_convert_to_slice(
&self,
err: &mut Diagnostic,
- trait_ref: ty::Binder<'tcx, ty::TraitRef<'tcx>>,
+ trait_ref: ty::PolyTraitRef<'tcx>,
candidate_impls: &[ImplCandidate<'tcx>],
span: Span,
) {
@@ -3890,7 +3776,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> {
.map(|trait_ref| trait_ref.trait_ref.self_ty())
.find(|t| is_slice(*t))
{
- let msg = &format!("convert the array to a `{}` slice instead", slice_ty);
+ let msg = format!("convert the array to a `{}` slice instead", slice_ty);
if let Ok(snippet) = self.tcx.sess.source_map().span_to_snippet(span) {
let mut suggestions = vec![];
@@ -4103,37 +3989,6 @@ impl NextTypeParamName for &[hir::GenericParam<'_>] {
}
}
-fn suggest_trait_object_return_type_alternatives(
- err: &mut Diagnostic,
- ret_ty: Span,
- trait_obj: &str,
- is_object_safe: bool,
-) {
- err.span_suggestion(
- ret_ty,
- &format!(
- "use `impl {}` as the return type if all return paths have the same type but you \
- want to expose only the trait in the signature",
- trait_obj,
- ),
- format!("impl {}", trait_obj),
- Applicability::MaybeIncorrect,
- );
- if is_object_safe {
- err.multipart_suggestion(
- &format!(
- "use a boxed trait object if all return paths implement trait `{}`",
- trait_obj,
- ),
- vec![
- (ret_ty.shrink_to_lo(), "Box<".to_string()),
- (ret_ty.shrink_to_hi(), ">".to_string()),
- ],
- Applicability::MaybeIncorrect,
- );
- }
-}
-
/// Collect the spans that we see the generic param `param_did`
struct ReplaceImplTraitVisitor<'a> {
ty_spans: &'a mut Vec<Span>,
diff --git a/compiler/rustc_trait_selection/src/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs
index 26cadab3e..2f85c32b5 100644
--- a/compiler/rustc_trait_selection/src/traits/fulfill.rs
+++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs
@@ -540,8 +540,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
use ty::ConstKind::Unevaluated;
match (c1.kind(), c2.kind()) {
(Unevaluated(a), Unevaluated(b))
- if a.def.did == b.def.did
- && tcx.def_kind(a.def.did) == DefKind::AssocConst =>
+ if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
{
if let Ok(new_obligations) = infcx
.at(&obligation.cause, obligation.param_env)
@@ -616,7 +615,7 @@ impl<'a, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'tcx> {
(Err(ErrorHandled::Reported(reported)), _)
| (_, Err(ErrorHandled::Reported(reported))) => ProcessResult::Error(
CodeSelectionError(SelectionError::NotConstEvaluatable(
- NotConstEvaluatable::Error(reported),
+ NotConstEvaluatable::Error(reported.into()),
)),
),
(Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => {
diff --git a/compiler/rustc_trait_selection/src/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs
index af567c074..2210ef975 100644
--- a/compiler/rustc_trait_selection/src/traits/misc.rs
+++ b/compiler/rustc_trait_selection/src/traits/misc.rs
@@ -2,23 +2,29 @@
use crate::traits::{self, ObligationCause, ObligationCtxt};
+use hir::LangItem;
use rustc_data_structures::fx::FxIndexSet;
use rustc_hir as hir;
use rustc_infer::infer::canonical::Canonical;
use rustc_infer::infer::{RegionResolutionError, TyCtxtInferExt};
use rustc_infer::traits::query::NoSolution;
use rustc_infer::{infer::outlives::env::OutlivesEnvironment, traits::FulfillmentError};
-use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
+use rustc_middle::ty::{self, AdtDef, GenericArg, List, ParamEnv, Ty, TyCtxt, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use super::outlives_bounds::InferCtxtExt;
pub enum CopyImplementationError<'tcx> {
- InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
+ InfringingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
NotAnAdt,
HasDestructor,
}
+pub enum ConstParamTyImplementationError<'tcx> {
+ InfrigingFields(Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>),
+ NotAnAdtOrBuiltinAllowed,
+}
+
pub enum InfringingFieldsReason<'tcx> {
Fulfill(Vec<FulfillmentError<'tcx>>),
Regions(Vec<RegionResolutionError<'tcx>>),
@@ -27,7 +33,10 @@ pub enum InfringingFieldsReason<'tcx> {
/// Checks that the fields of the type (an ADT) all implement copy.
///
/// If fields don't implement copy, return an error containing a list of
-/// those violating fields. If it's not an ADT, returns `Err(NotAnAdt)`.
+/// those violating fields.
+///
+/// If it's not an ADT, int ty, `bool`, float ty, `char`, raw pointer, `!`,
+/// a reference or an array returns `Err(NotAnAdt)`.
pub fn type_allowed_to_implement_copy<'tcx>(
tcx: TyCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
@@ -47,12 +56,82 @@ pub fn type_allowed_to_implement_copy<'tcx>(
| ty::Ref(_, _, hir::Mutability::Not)
| ty::Array(..) => return Ok(()),
- ty::Adt(adt, substs) => (adt, substs),
+ &ty::Adt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt),
};
- let copy_def_id = tcx.require_lang_item(hir::LangItem::Copy, Some(parent_cause.span));
+ all_fields_implement_trait(
+ tcx,
+ param_env,
+ self_type,
+ adt,
+ substs,
+ parent_cause,
+ hir::LangItem::Copy,
+ )
+ .map_err(CopyImplementationError::InfringingFields)?;
+
+ if adt.has_dtor(tcx) {
+ return Err(CopyImplementationError::HasDestructor);
+ }
+
+ Ok(())
+}
+
+/// Checks that the fields of the type (an ADT) all implement `ConstParamTy`.
+///
+/// If fields don't implement `ConstParamTy`, return an error containing a list of
+/// those violating fields.
+///
+/// If it's not an ADT, int ty, `bool` or `char`, returns `Err(NotAnAdtOrBuiltinAllowed)`.
+pub fn type_allowed_to_implement_const_param_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ self_type: Ty<'tcx>,
+ parent_cause: ObligationCause<'tcx>,
+) -> Result<(), ConstParamTyImplementationError<'tcx>> {
+ let (adt, substs) = match self_type.kind() {
+ // `core` provides these impls.
+ ty::Uint(_)
+ | ty::Int(_)
+ | ty::Bool
+ | ty::Char
+ | ty::Str
+ | ty::Array(..)
+ | ty::Slice(_)
+ | ty::Ref(.., hir::Mutability::Not) => return Ok(()),
+
+ &ty::Adt(adt, substs) => (adt, substs),
+
+ _ => return Err(ConstParamTyImplementationError::NotAnAdtOrBuiltinAllowed),
+ };
+
+ all_fields_implement_trait(
+ tcx,
+ param_env,
+ self_type,
+ adt,
+ substs,
+ parent_cause,
+ hir::LangItem::ConstParamTy,
+ )
+ .map_err(ConstParamTyImplementationError::InfrigingFields)?;
+
+ Ok(())
+}
+
+/// Check that all fields of a given `adt` implement `lang_item` trait.
+pub fn all_fields_implement_trait<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ self_type: Ty<'tcx>,
+ adt: AdtDef<'tcx>,
+ substs: &'tcx List<GenericArg<'tcx>>,
+ parent_cause: ObligationCause<'tcx>,
+ lang_item: LangItem,
+) -> Result<(), Vec<(&'tcx ty::FieldDef, Ty<'tcx>, InfringingFieldsReason<'tcx>)>> {
+ let trait_def_id = tcx.require_lang_item(lang_item, Some(parent_cause.span));
let mut infringing = Vec::new();
for variant in adt.variants() {
@@ -93,7 +172,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
// between expected and found const-generic types. Don't report an
// additional copy error here, since it's not typically useful.
if !normalization_errors.is_empty() || ty.references_error() {
- tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking Copy implementation"));
+ tcx.sess.delay_span_bug(field_span, format!("couldn't normalize struct field `{unnormalized_ty}` when checking {tr} implementation", tr = tcx.def_path_str(trait_def_id)));
continue;
}
@@ -101,7 +180,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
ObligationCause::dummy_with_span(field_ty_span),
param_env,
ty,
- copy_def_id,
+ trait_def_id,
);
let errors = ocx.select_all_or_error();
if !errors.is_empty() {
@@ -124,15 +203,7 @@ pub fn type_allowed_to_implement_copy<'tcx>(
}
}
- if !infringing.is_empty() {
- return Err(CopyImplementationError::InfrigingFields(infringing));
- }
-
- if adt.has_dtor(tcx) {
- return Err(CopyImplementationError::HasDestructor);
- }
-
- Ok(())
+ if infringing.is_empty() { Ok(()) } else { Err(infringing) }
}
pub fn check_tys_might_be_eq<'tcx>(
diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs
index 8a203dec8..f265230ff 100644
--- a/compiler/rustc_trait_selection/src/traits/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/mod.rs
@@ -17,6 +17,7 @@ pub mod query;
mod select;
mod specialize;
mod structural_match;
+mod structural_normalize;
mod util;
mod vtable;
pub mod wf;
@@ -26,6 +27,7 @@ use crate::infer::{InferCtxt, TyCtxtInferExt};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
use crate::traits::query::evaluate_obligation::InferCtxtExt as _;
use rustc_errors::ErrorGuaranteed;
+use rustc_middle::query::Providers;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeSuperVisitable};
@@ -49,20 +51,24 @@ pub use self::object_safety::astconv_object_safety_violations;
pub use self::object_safety::is_vtable_safe_method;
pub use self::object_safety::MethodViolationCode;
pub use self::object_safety::ObjectSafetyViolation;
-pub use self::project::{normalize_projection_type, NormalizeExt};
+pub use self::project::NormalizeExt;
+pub use self::project::{normalize_inherent_projection, normalize_projection_type};
pub use self::select::{EvaluationCache, SelectionCache, SelectionContext};
pub use self::select::{EvaluationResult, IntercrateAmbiguityCause, OverflowError};
pub use self::specialize::specialization_graph::FutureCompatOverlapError;
pub use self::specialize::specialization_graph::FutureCompatOverlapErrorKind;
-pub use self::specialize::{specialization_graph, translate_substs, OverlapError};
+pub use self::specialize::{
+ specialization_graph, translate_substs, translate_substs_with_cause, OverlapError,
+};
pub use self::structural_match::{
search_for_adt_const_param_violation, search_for_structural_match_violation,
};
+pub use self::structural_normalize::StructurallyNormalizeExt;
pub use self::util::elaborate;
pub use self::util::{expand_trait_aliases, TraitAliasExpander};
pub use self::util::{get_vtable_index_of_object_method, impl_item_is_final, upcast_choices};
pub use self::util::{
- supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_type,
+ supertrait_def_ids, supertraits, transitive_bounds, transitive_bounds_that_define_assoc_item,
SupertraitDefIds,
};
@@ -127,7 +133,7 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
ty: Ty<'tcx>,
def_id: DefId,
) -> bool {
- let trait_ref = ty::Binder::dummy(infcx.tcx.mk_trait_ref(def_id, [ty]));
+ let trait_ref = ty::TraitRef::new(infcx.tcx, def_id, [ty]);
pred_known_to_hold_modulo_regions(infcx, param_env, trait_ref.without_const())
}
@@ -139,35 +145,36 @@ pub fn type_known_to_meet_bound_modulo_regions<'tcx>(
fn pred_known_to_hold_modulo_regions<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
- pred: impl ToPredicate<'tcx> + TypeVisitable<TyCtxt<'tcx>>,
+ pred: impl ToPredicate<'tcx>,
) -> bool {
- let has_non_region_infer = pred.has_non_region_infer();
let obligation = Obligation::new(infcx.tcx, ObligationCause::dummy(), param_env, pred);
let result = infcx.evaluate_obligation_no_overflow(&obligation);
debug!(?result);
- if result.must_apply_modulo_regions() && !has_non_region_infer {
+ if result.must_apply_modulo_regions() {
true
} else if result.may_apply() {
- // Because of inference "guessing", selection can sometimes claim
- // to succeed while the success requires a guess. To ensure
- // this function's result remains infallible, we must confirm
- // that guess. While imperfect, I believe this is sound.
-
- // The handling of regions in this area of the code is terrible,
- // see issue #29149. We should be able to improve on this with
- // NLL.
- let ocx = ObligationCtxt::new(infcx);
- ocx.register_obligation(obligation);
- let errors = ocx.select_all_or_error();
- match errors.as_slice() {
- [] => true,
- errors => {
- debug!(?errors);
- false
+ // Sometimes obligations are ambiguous because the recursive evaluator
+ // is not smart enough, so we fall back to fulfillment when we're not certain
+ // that an obligation holds or not. Even still, we must make sure that
+ // the we do no inference in the process of checking this obligation.
+ let goal = infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
+ infcx.probe(|_| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ ocx.register_obligation(obligation);
+
+ let errors = ocx.select_all_or_error();
+ match errors.as_slice() {
+ // Only known to hold if we did no inference.
+ [] => infcx.shallow_resolve(goal) == goal,
+
+ errors => {
+ debug!(?errors);
+ false
+ }
}
- }
+ })
} else {
false
}
@@ -203,7 +210,7 @@ fn do_normalize_predicates<'tcx>(
}
};
- debug!("do_normalize_predictes: normalized predicates = {:?}", predicates);
+ debug!("do_normalize_predicates: normalized predicates = {:?}", predicates);
// We can use the `elaborated_env` here; the region code only
// cares about declarations like `'a: 'b`.
@@ -414,7 +421,7 @@ fn subst_and_check_impossible_predicates<'tcx>(
predicates.push(ty::Binder::dummy(trait_ref).to_predicate(tcx));
}
- predicates.retain(|predicate| !predicate.needs_subst());
+ predicates.retain(|predicate| !predicate.has_param());
let result = impossible_predicates(tcx, predicates);
debug!("subst_and_check_impossible_predicates(key={:?}) = {:?}", key, result);
@@ -450,7 +457,7 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
{
return ControlFlow::Break(());
}
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
fn visit_const(&mut self, ct: ty::Const<'tcx>) -> ControlFlow<Self::BreakTy> {
if let ty::ConstKind::Param(param) = ct.kind()
@@ -495,10 +502,10 @@ fn is_impossible_method(tcx: TyCtxt<'_>, (impl_def_id, trait_item_def_id): (DefI
false
}
-pub fn provide(providers: &mut ty::query::Providers) {
+pub fn provide(providers: &mut Providers) {
object_safety::provide(providers);
vtable::provide(providers);
- *providers = ty::query::Providers {
+ *providers = Providers {
specialization_graph_of: specialize::specialization_graph_provider,
specializes: specialize::specializes,
subst_and_check_impossible_predicates,
diff --git a/compiler/rustc_trait_selection/src/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs
index b8ad1925e..c81bf6ebc 100644
--- a/compiler/rustc_trait_selection/src/traits/object_safety.rs
+++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs
@@ -16,6 +16,7 @@ use crate::traits::{self, Obligation, ObligationCause};
use rustc_errors::{DelayDm, FatalError, MultiSpan};
use rustc_hir as hir;
use rustc_hir::def_id::DefId;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::{GenericArg, InternalSubsts};
use rustc_middle::ty::{
self, EarlyBinder, Ty, TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
@@ -279,7 +280,7 @@ fn predicates_reference_self(
trait_def_id: DefId,
supertraits_only: bool,
) -> SmallVec<[Span; 1]> {
- let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
+ let trait_ref = ty::Binder::dummy(ty::TraitRef::identity(tcx, trait_def_id));
let predicates = if supertraits_only {
tcx.super_predicates_of(trait_def_id)
} else {
@@ -297,8 +298,8 @@ fn bounds_reference_self(tcx: TyCtxt<'_>, trait_def_id: DefId) -> SmallVec<[Span
tcx.associated_items(trait_def_id)
.in_definition_order()
.filter(|item| item.kind == ty::AssocKind::Type)
- .flat_map(|item| tcx.explicit_item_bounds(item.def_id))
- .filter_map(|pred_span| predicate_references_self(tcx, *pred_span))
+ .flat_map(|item| tcx.explicit_item_bounds(item.def_id).subst_identity_iter_copied())
+ .filter_map(|pred_span| predicate_references_self(tcx, pred_span))
.collect()
}
@@ -525,7 +526,7 @@ fn virtual_call_violation_for_method<'tcx>(
// #78372
tcx.sess.delay_span_bug(
tcx.def_span(method.def_id),
- &format!("error: {}\n while computing layout for type {:?}", err, ty),
+ format!("error: {}\n while computing layout for type {:?}", err, ty),
);
None
}
@@ -541,7 +542,7 @@ fn virtual_call_violation_for_method<'tcx>(
abi => {
tcx.sess.delay_span_bug(
tcx.def_span(method.def_id),
- &format!(
+ format!(
"receiver when `Self = ()` should have a Scalar ABI; found {:?}",
abi
),
@@ -560,7 +561,7 @@ fn virtual_call_violation_for_method<'tcx>(
abi => {
tcx.sess.delay_span_bug(
tcx.def_span(method.def_id),
- &format!(
+ format!(
"receiver when `Self = {}` should have a ScalarPair ABI; found {:?}",
trait_object_ty, abi
),
@@ -661,9 +662,9 @@ fn object_ty_for_trait<'tcx>(
let trait_ref = ty::TraitRef::identity(tcx, trait_def_id);
debug!(?trait_ref);
- let trait_predicate = trait_ref.map_bound(|trait_ref| {
- ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref))
- });
+ let trait_predicate = ty::Binder::dummy(ty::ExistentialPredicate::Trait(
+ ty::ExistentialTraitRef::erase_self_ty(tcx, trait_ref),
+ ));
debug!(?trait_predicate);
let pred: ty::Predicate<'tcx> = trait_ref.to_predicate(tcx);
@@ -769,11 +770,10 @@ fn receiver_is_dispatchable<'tcx>(
let param_env = tcx.param_env(method.def_id);
// Self: Unsize<U>
- let unsize_predicate = ty::Binder::dummy(
- tcx.mk_trait_ref(unsize_did, [tcx.types.self_param, unsized_self_ty]),
- )
- .without_const()
- .to_predicate(tcx);
+ let unsize_predicate =
+ ty::TraitRef::new(tcx, unsize_did, [tcx.types.self_param, unsized_self_ty])
+ .without_const()
+ .to_predicate(tcx);
// U: Trait<Arg1, ..., ArgN>
let trait_predicate = {
@@ -782,7 +782,7 @@ fn receiver_is_dispatchable<'tcx>(
if param.index == 0 { unsized_self_ty.into() } else { tcx.mk_param_from_def(param) }
});
- ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, substs)).to_predicate(tcx)
+ ty::TraitRef::new(tcx, trait_def_id, substs).to_predicate(tcx)
};
let caller_bounds =
@@ -797,9 +797,8 @@ fn receiver_is_dispatchable<'tcx>(
// Receiver: DispatchFromDyn<Receiver[Self => U]>
let obligation = {
- let predicate = ty::Binder::dummy(
- tcx.mk_trait_ref(dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]),
- );
+ let predicate =
+ ty::TraitRef::new(tcx, dispatch_from_dyn_did, [receiver_ty, unsized_receiver_ty]);
Obligation::new(tcx, ObligationCause::dummy(), param_env, predicate)
};
@@ -882,7 +881,8 @@ fn contains_illegal_self_type_reference<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
// Compute supertraits of current trait lazily.
if self.supertraits.is_none() {
- let trait_ref = ty::TraitRef::identity(self.tcx, self.trait_def_id);
+ let trait_ref =
+ ty::Binder::dummy(ty::TraitRef::identity(self.tcx, self.trait_def_id));
self.supertraits = Some(
traits::supertraits(self.tcx, trait_ref).map(|t| t.def_id()).collect(),
);
@@ -948,7 +948,6 @@ pub fn contains_illegal_impl_trait_in_trait<'tcx>(
})
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { object_safety_violations, check_is_object_safe, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { object_safety_violations, check_is_object_safe, ..*providers };
}
diff --git a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
index cff3d277a..f8d056e32 100644
--- a/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/outlives_bounds.rs
@@ -1,9 +1,9 @@
use crate::infer::InferCtxt;
-use crate::traits::query::type_op::{self, TypeOp, TypeOpOutput};
-use crate::traits::query::NoSolution;
use crate::traits::{ObligationCause, ObligationCtxt};
use rustc_data_structures::fx::FxIndexSet;
use rustc_infer::infer::resolve::OpportunisticRegionResolver;
+use rustc_infer::infer::InferOk;
+use rustc_middle::infer::canonical::{OriginalQueryValues, QueryRegionConstraints};
use rustc_middle::ty::{self, ParamEnv, Ty, TypeFolder, TypeVisitableExt};
use rustc_span::def_id::LocalDefId;
@@ -55,26 +55,42 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
) -> Vec<OutlivesBound<'tcx>> {
let ty = self.resolve_vars_if_possible(ty);
let ty = OpportunisticRegionResolver::new(self).fold_ty(ty);
- assert!(!ty.needs_infer());
- let span = self.tcx.def_span(body_id);
- let result = param_env
- .and(type_op::implied_outlives_bounds::ImpliedOutlivesBounds { ty })
- .fully_perform(self);
- let result = match result {
- Ok(r) => r,
- Err(NoSolution) => {
- self.tcx.sess.delay_span_bug(
- span,
- "implied_outlives_bounds failed to solve all obligations",
- );
- return vec![];
- }
+ // We do not expect existential variables in implied bounds.
+ // We may however encounter unconstrained lifetime variables in invalid
+ // code. See #110161 for context.
+ assert!(!ty.has_non_region_infer());
+ if ty.has_infer() {
+ self.tcx.sess.delay_span_bug(
+ self.tcx.def_span(body_id),
+ "skipped implied_outlives_bounds due to unconstrained lifetimes",
+ );
+ return vec![];
+ }
+
+ let mut canonical_var_values = OriginalQueryValues::default();
+ let canonical_ty =
+ self.canonicalize_query_keep_static(param_env.and(ty), &mut canonical_var_values);
+ let Ok(canonical_result) = self.tcx.implied_outlives_bounds(canonical_ty) else {
+ return vec![];
+ };
+
+ let mut constraints = QueryRegionConstraints::default();
+ let Ok(InferOk { value, obligations }) = self
+ .instantiate_nll_query_response_and_region_obligations(
+ &ObligationCause::dummy(),
+ param_env,
+ &canonical_var_values,
+ canonical_result,
+ &mut constraints,
+ ) else {
+ return vec![];
};
+ assert_eq!(&obligations, &[]);
- let TypeOpOutput { output, constraints, .. } = result;
+ if !constraints.is_empty() {
+ let span = self.tcx.def_span(body_id);
- if let Some(constraints) = constraints {
debug!(?constraints);
if !constraints.member_constraints.is_empty() {
span_bug!(span, "{:#?}", constraints.member_constraints);
@@ -101,7 +117,7 @@ impl<'a, 'tcx: 'a> InferCtxtExt<'a, 'tcx> for InferCtxt<'tcx> {
}
};
- output
+ value
}
fn implied_bounds_tys(
diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs
index 826fc63ca..510698971 100644
--- a/compiler/rustc_trait_selection/src/traits/project.rs
+++ b/compiler/rustc_trait_selection/src/traits/project.rs
@@ -16,6 +16,7 @@ use super::{
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
+use crate::errors::InherentProjectionNormalizationOverflow;
use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
use crate::infer::{InferCtxt, InferOk, LateBoundRegionConversionTime};
use crate::traits::error_reporting::TypeErrCtxtExt as _;
@@ -370,10 +371,14 @@ pub(crate) fn needs_normalization<'tcx, T: TypeVisitable<TyCtxt<'tcx>>>(
reveal: Reveal,
) -> bool {
match reveal {
- Reveal::UserFacing => value
- .has_type_flags(ty::TypeFlags::HAS_TY_PROJECTION | ty::TypeFlags::HAS_CT_PROJECTION),
+ Reveal::UserFacing => value.has_type_flags(
+ ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
+ | ty::TypeFlags::HAS_CT_PROJECTION,
+ ),
Reveal::All => value.has_type_flags(
ty::TypeFlags::HAS_TY_PROJECTION
+ | ty::TypeFlags::HAS_TY_INHERENT
| ty::TypeFlags::HAS_TY_OPAQUE
| ty::TypeFlags::HAS_CT_PROJECTION,
),
@@ -616,6 +621,51 @@ impl<'a, 'b, 'tcx> TypeFolder<TyCtxt<'tcx>> for AssocTypeNormalizer<'a, 'b, 'tcx
);
normalized_ty
}
+
+ ty::Inherent if !data.has_escaping_bound_vars() => {
+ // This branch is *mostly* just an optimization: when we don't
+ // have escaping bound vars, we don't need to replace them with
+ // placeholders (see branch below). *Also*, we know that we can
+ // register an obligation to *later* project, since we know
+ // there won't be bound vars there.
+
+ let data = data.fold_with(self);
+
+ // FIXME(inherent_associated_types): Do we need to honor `self.eager_inference_replacement`
+ // here like `ty::Projection`?
+ normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ )
+ }
+
+ ty::Inherent => {
+ let infcx = self.selcx.infcx;
+ let (data, mapped_regions, mapped_types, mapped_consts) =
+ BoundVarReplacer::replace_bound_vars(infcx, &mut self.universes, data);
+ let data = data.fold_with(self);
+ let ty = normalize_inherent_projection(
+ self.selcx,
+ self.param_env,
+ data,
+ self.cause.clone(),
+ self.depth,
+ &mut self.obligations,
+ );
+
+ PlaceholderReplacer::replace_placeholders(
+ infcx,
+ mapped_regions,
+ mapped_types,
+ mapped_consts,
+ &self.universes,
+ ty,
+ )
+ }
}
}
@@ -1204,6 +1254,115 @@ fn normalize_to_error<'a, 'tcx>(
Normalized { value: new_value, obligations: vec![trait_obligation] }
}
+/// Confirm and normalize the given inherent projection.
+#[instrument(level = "debug", skip(selcx, param_env, cause, obligations))]
+pub fn normalize_inherent_projection<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> Ty<'tcx> {
+ let tcx = selcx.tcx();
+
+ if !tcx.recursion_limit().value_within_limit(depth) {
+ // Halt compilation because it is important that overflows never be masked.
+ tcx.sess.emit_fatal(InherentProjectionNormalizationOverflow {
+ span: cause.span,
+ ty: alias_ty.to_string(),
+ });
+ }
+
+ let substs = compute_inherent_assoc_ty_substs(
+ selcx,
+ param_env,
+ alias_ty,
+ cause.clone(),
+ depth,
+ obligations,
+ );
+
+ // Register the obligations arising from the impl and from the associated type itself.
+ let predicates = tcx.predicates_of(alias_ty.def_id).instantiate(tcx, substs);
+ for (predicate, span) in predicates {
+ let predicate = normalize_with_depth_to(
+ selcx,
+ param_env,
+ cause.clone(),
+ depth + 1,
+ predicate,
+ obligations,
+ );
+
+ let nested_cause = ObligationCause::new(
+ cause.span,
+ cause.body_id,
+ // FIXME(inherent_associated_types): Since we can't pass along the self type to the
+ // cause code, inherent projections will be printed with identity substitutions in
+ // diagnostics which is not ideal.
+ // Consider creating separate cause codes for this specific situation.
+ if span.is_dummy() {
+ super::ItemObligation(alias_ty.def_id)
+ } else {
+ super::BindingObligation(alias_ty.def_id, span)
+ },
+ );
+
+ obligations.push(Obligation::with_depth(
+ tcx,
+ nested_cause,
+ depth + 1,
+ param_env,
+ predicate,
+ ));
+ }
+
+ let ty = tcx.type_of(alias_ty.def_id).subst(tcx, substs);
+
+ let mut ty = selcx.infcx.resolve_vars_if_possible(ty);
+ if ty.has_projections() {
+ ty = normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, ty, obligations);
+ }
+
+ ty
+}
+
+pub fn compute_inherent_assoc_ty_substs<'a, 'b, 'tcx>(
+ selcx: &'a mut SelectionContext<'b, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ alias_ty: ty::AliasTy<'tcx>,
+ cause: ObligationCause<'tcx>,
+ depth: usize,
+ obligations: &mut Vec<PredicateObligation<'tcx>>,
+) -> ty::SubstsRef<'tcx> {
+ let tcx = selcx.tcx();
+
+ let impl_def_id = tcx.parent(alias_ty.def_id);
+ let impl_substs = selcx.infcx.fresh_substs_for_item(cause.span, impl_def_id);
+
+ let impl_ty = tcx.type_of(impl_def_id).subst(tcx, impl_substs);
+ let impl_ty =
+ normalize_with_depth_to(selcx, param_env, cause.clone(), depth + 1, impl_ty, obligations);
+
+ // Infer the generic parameters of the impl by unifying the
+ // impl type with the self type of the projection.
+ let self_ty = alias_ty.self_ty();
+ match selcx.infcx.at(&cause, param_env).eq(DefineOpaqueTypes::No, impl_ty, self_ty) {
+ Ok(mut ok) => obligations.append(&mut ok.obligations),
+ Err(_) => {
+ tcx.sess.delay_span_bug(
+ cause.span,
+ format!(
+ "{self_ty:?} was a subtype of {impl_ty:?} during selection but now it is not"
+ ),
+ );
+ }
+ }
+
+ alias_ty.rebase_substs_onto_impl(impl_substs, tcx)
+}
+
enum Projected<'tcx> {
Progress(Progress<'tcx>),
NoProgress(ty::Term<'tcx>),
@@ -1272,14 +1431,29 @@ fn project<'cx, 'tcx>(
ProjectionCandidateSet::Single(candidate) => {
Ok(Projected::Progress(confirm_candidate(selcx, obligation, candidate)))
}
- ProjectionCandidateSet::None => Ok(Projected::NoProgress(
- // FIXME(associated_const_generics): this may need to change in the future?
- // need to investigate whether or not this is fine.
- selcx
- .tcx()
- .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
- .into(),
- )),
+ ProjectionCandidateSet::None => {
+ let tcx = selcx.tcx();
+ let term = match tcx.def_kind(obligation.predicate.def_id) {
+ DefKind::AssocTy | DefKind::ImplTraitPlaceholder => tcx
+ .mk_projection(obligation.predicate.def_id, obligation.predicate.substs)
+ .into(),
+ DefKind::AssocConst => tcx
+ .mk_const(
+ ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(
+ obligation.predicate.def_id,
+ obligation.predicate.substs,
+ )),
+ tcx.type_of(obligation.predicate.def_id)
+ .subst(tcx, obligation.predicate.substs),
+ )
+ .into(),
+ kind => {
+ bug!("unknown projection def-id: {}", kind.descr(obligation.predicate.def_id))
+ }
+ };
+
+ Ok(Projected::NoProgress(term))
+ }
// Error occurred while trying to processing impls.
ProjectionCandidateSet::Error(e) => Err(ProjectionError::TraitSelectionError(e)),
// Inherent ambiguity that prevents us from even enumerating the
@@ -1304,7 +1478,7 @@ fn assemble_candidate_for_impl_trait_in_trait<'cx, 'tcx>(
let trait_substs =
obligation.predicate.substs.truncate_to(tcx, tcx.generics_of(trait_def_id));
// FIXME(named-returns): Binders
- let trait_predicate = ty::Binder::dummy(tcx.mk_trait_ref(trait_def_id, trait_substs));
+ let trait_predicate = ty::TraitRef::new(tcx, trait_def_id, trait_substs);
let _ = selcx.infcx.commit_if_ok(|_| {
match selcx.select(&obligation.with(tcx, trait_predicate)) {
@@ -1369,7 +1543,10 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>(
// Check whether the self-type is itself a projection.
// If so, extract what we know from the trait and try to come up with a good answer.
let bounds = match *obligation.predicate.self_ty().kind() {
- ty::Alias(_, ref data) => tcx.item_bounds(data.def_id).subst(tcx, data.substs),
+ // Excluding IATs here as they don't have meaningful item bounds.
+ ty::Alias(ty::Projection | ty::Opaque, ref data) => {
+ tcx.item_bounds(data.def_id).subst(tcx, data.substs)
+ }
ty::Infer(ty::TyVar(_)) => {
// If the self-type is an inference variable, then it MAY wind up
// being a projected type, so induce an ambiguity.
@@ -1667,10 +1844,8 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
if selcx.infcx.predicate_must_hold_modulo_regions(
&obligation.with(
selcx.tcx(),
- ty::Binder::dummy(
- selcx.tcx().at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
- )
- .without_const(),
+ ty::TraitRef::from_lang_item(selcx.tcx(), LangItem::Sized, obligation.cause.span(),[self_ty])
+ .without_const(),
),
) =>
{
@@ -1734,7 +1909,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>(
// These traits have no associated types.
selcx.tcx().sess.delay_span_bug(
obligation.cause.span,
- &format!("Cannot project an associated type from `{:?}`", impl_source),
+ format!("Cannot project an associated type from `{:?}`", impl_source),
);
return Err(());
}
@@ -1933,8 +2108,11 @@ fn confirm_builtin_candidate<'cx, 'tcx>(
)
});
if check_is_sized {
- let sized_predicate = ty::Binder::dummy(
- tcx.at(obligation.cause.span()).mk_trait_ref(LangItem::Sized, [self_ty]),
+ let sized_predicate = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ obligation.cause.span(),
+ [self_ty],
)
.without_const();
obligations.push(obligation.with(tcx, sized_predicate));
@@ -2085,7 +2263,7 @@ fn confirm_param_env_candidate<'cx, 'tcx>(
obligation, poly_cache_entry, e,
);
debug!("confirm_param_env_candidate: {}", msg);
- let err = infcx.tcx.ty_error_with_message(obligation.cause.span, &msg);
+ let err = infcx.tcx.ty_error_with_message(obligation.cause.span, msg);
Progress { term: err.into(), obligations: vec![] }
}
}
@@ -2131,9 +2309,8 @@ fn confirm_impl_candidate<'cx, 'tcx>(
let ty = tcx.type_of(assoc_ty.item.def_id);
let is_const = matches!(tcx.def_kind(assoc_ty.item.def_id), DefKind::AssocConst);
let term: ty::EarlyBinder<ty::Term<'tcx>> = if is_const {
- let identity_substs =
- crate::traits::InternalSubsts::identity_for_item(tcx, assoc_ty.item.def_id);
- let did = ty::WithOptConstParam::unknown(assoc_ty.item.def_id);
+ let did = assoc_ty.item.def_id;
+ let identity_substs = crate::traits::InternalSubsts::identity_for_item(tcx, did);
let kind = ty::ConstKind::Unevaluated(ty::UnevaluatedConst::new(did, identity_substs));
ty.map_bound(|ty| tcx.mk_const(kind, ty).into())
} else {
@@ -2277,11 +2454,10 @@ fn confirm_impl_trait_in_trait_candidate<'tcx>(
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
- tcx.bound_return_position_impl_trait_in_trait_tys(impl_fn_def_id)
- .map_bound(|tys| {
- tys.map_or_else(|guar| tcx.ty_error(guar), |tys| tys[&obligation.predicate.def_id])
- })
- .subst(tcx, impl_fn_substs),
+ tcx.collect_return_position_impl_trait_in_trait_tys(impl_fn_def_id).map_or_else(
+ |guar| tcx.ty_error(guar),
+ |tys| tys[&obligation.predicate.def_id].subst(tcx, impl_fn_substs),
+ ),
&mut obligations,
);
diff --git a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
index 455b53bfb..4e4172e7f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs
@@ -1,6 +1,11 @@
-use rustc_middle::ty::{self, Ty, TyCtxt};
+use crate::traits::query::normalize::QueryNormalizeExt;
+use crate::traits::query::NoSolution;
+use crate::traits::{Normalized, ObligationCause, ObligationCtxt};
-pub use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
+use rustc_data_structures::fx::FxHashSet;
+use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
+use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
+use rustc_span::source_map::{Span, DUMMY_SP};
/// This returns true if the type `ty` is "trivial" for
/// dropck-outlives -- that is, if it doesn't require any types to
@@ -71,3 +76,263 @@ pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool {
| ty::Generator(..) => false,
}
}
+
+pub fn compute_dropck_outlives_inner<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ goal: ParamEnvAnd<'tcx, Ty<'tcx>>,
+) -> Result<DropckOutlivesResult<'tcx>, NoSolution> {
+ 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_inner`. 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_inner` 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_inner(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(..) {
+ let Normalized { value: ty, obligations } =
+ ocx.infcx.at(&cause, param_env).query_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::Alias(..) => {
+ result.kinds.push(ty.into());
+ }
+
+ _ => {
+ if ty_set.insert(ty) {
+ ty_stack.push((ty, depth + 1));
+ }
+ }
+ }
+ }
+ }
+
+ debug!("dropck_outlives: result = {:#?}", result);
+ Ok(result)
+}
+
+/// Returns a set of constraints that needs to be satisfied in
+/// order for `ty` to be valid for destruction.
+pub fn dtorck_constraint_for_ty_inner<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ span: Span,
+ for_ty: Ty<'tcx>,
+ depth: usize,
+ ty: Ty<'tcx>,
+ constraints: &mut DropckConstraint<'tcx>,
+) -> Result<(), NoSolution> {
+ debug!("dtorck_constraint_for_ty_inner({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
+
+ if !tcx.recursion_limit().value_within_limit(depth) {
+ constraints.overflows.push(ty);
+ return Ok(());
+ }
+
+ if trivial_dropck_outlives(tcx, ty) {
+ return Ok(());
+ }
+
+ match ty.kind() {
+ ty::Bool
+ | ty::Char
+ | ty::Int(_)
+ | ty::Uint(_)
+ | ty::Float(_)
+ | ty::Str
+ | ty::Never
+ | ty::Foreign(..)
+ | ty::RawPtr(..)
+ | ty::Ref(..)
+ | ty::FnDef(..)
+ | ty::FnPtr(_)
+ | ty::GeneratorWitness(..)
+ | ty::GeneratorWitnessMIR(..) => {
+ // these types never have a destructor
+ }
+
+ ty::Array(ety, _) | ty::Slice(ety) => {
+ // single-element containers, behave like their element
+ rustc_data_structures::stack::ensure_sufficient_stack(|| {
+ dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, *ety, constraints)
+ })?;
+ }
+
+ ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
+ for ty in tys.iter() {
+ dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+ }
+ Ok::<_, NoSolution>(())
+ })?,
+
+ ty::Closure(_, substs) => {
+ if !substs.as_closure().is_valid() {
+ // By the time this code runs, all type variables ought to
+ // be fully resolved.
+
+ tcx.sess.delay_span_bug(
+ span,
+ format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
+ );
+ return Err(NoSolution);
+ }
+
+ rustc_data_structures::stack::ensure_sufficient_stack(|| {
+ for ty in substs.as_closure().upvar_tys() {
+ dtorck_constraint_for_ty_inner(tcx, span, for_ty, depth + 1, ty, constraints)?;
+ }
+ Ok::<_, NoSolution>(())
+ })?
+ }
+
+ ty::Generator(_, substs, _movability) => {
+ // rust-lang/rust#49918: types can be constructed, stored
+ // in the interior, and sit idle when generator yields
+ // (and is subsequently dropped).
+ //
+ // It would be nice to descend into interior of a
+ // generator to determine what effects dropping it might
+ // have (by looking at any drop effects associated with
+ // its interior).
+ //
+ // However, the interior's representation uses things like
+ // GeneratorWitness that explicitly assume they are not
+ // traversed in such a manner. So instead, we will
+ // simplify things for now by treating all generators as
+ // if they were like trait objects, where its upvars must
+ // all be alive for the generator's (potential)
+ // destructor.
+ //
+ // In particular, skipping over `_interior` is safe
+ // because any side-effects from dropping `_interior` can
+ // only take place through references with lifetimes
+ // derived from lifetimes attached to the upvars and resume
+ // argument, and we *do* incorporate those here.
+
+ if !substs.as_generator().is_valid() {
+ // By the time this code runs, all type variables ought to
+ // be fully resolved.
+ tcx.sess.delay_span_bug(
+ span,
+ format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
+ );
+ return Err(NoSolution);
+ }
+
+ constraints.outlives.extend(
+ substs
+ .as_generator()
+ .upvar_tys()
+ .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
+ );
+ constraints.outlives.push(substs.as_generator().resume_ty().into());
+ }
+
+ ty::Adt(def, substs) => {
+ let DropckConstraint { dtorck_types, outlives, overflows } =
+ tcx.at(span).adt_dtorck_constraint(def.did())?;
+ // FIXME: we can try to recursively `dtorck_constraint_on_ty`
+ // there, but that needs some way to handle cycles.
+ constraints
+ .dtorck_types
+ .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
+ constraints
+ .outlives
+ .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
+ constraints
+ .overflows
+ .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
+ }
+
+ // Objects must be alive in order for their destructor
+ // to be called.
+ ty::Dynamic(..) => {
+ constraints.outlives.push(ty.into());
+ }
+
+ // Types that can't be resolved. Pass them forward.
+ ty::Alias(..) | ty::Param(..) => {
+ constraints.dtorck_types.push(ty);
+ }
+
+ ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
+ // By the time this code runs, all type variables ought to
+ // be fully resolved.
+ return Err(NoSolution);
+ }
+ }
+
+ Ok(())
+}
diff --git a/compiler/rustc_trait_selection/src/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
index a986a9b6a..8bf934cb7 100644
--- a/compiler/rustc_trait_selection/src/traits/query/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs
@@ -257,11 +257,11 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
ty::Opaque => ty.try_super_fold_with(self)?,
- ty::Projection => {
+ ty::Projection | ty::Inherent => {
// See note in `rustc_trait_selection::traits::project`
- let tcx = self.infcx.tcx;
let infcx = self.infcx;
+ let tcx = infcx.tcx;
// Just an optimization: When we don't have escaping bound vars,
// we don't need to replace them with placeholders.
let (data, maps) = if data.has_escaping_bound_vars() {
@@ -276,12 +276,15 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
let mut orig_values = OriginalQueryValues::default();
// HACK(matthewjasper) `'static` is special-cased in selection,
// so we cannot canonicalize it.
- let c_data = self
- .infcx
+ let c_data = infcx
.canonicalize_query_keep_static(self.param_env.and(data), &mut orig_values);
debug!("QueryNormalizer: c_data = {:#?}", c_data);
debug!("QueryNormalizer: orig_values = {:#?}", orig_values);
- let result = tcx.normalize_projection_ty(c_data)?;
+ let result = match kind {
+ ty::Projection => tcx.normalize_projection_ty(c_data),
+ ty::Inherent => tcx.normalize_inherent_projection_ty(c_data),
+ _ => unreachable!(),
+ }?;
// We don't expect ambiguity.
if result.is_ambiguous() {
// Rustdoc normalizes possibly not well-formed types, so only
@@ -294,8 +297,8 @@ impl<'cx, 'tcx> FallibleTypeFolder<TyCtxt<'tcx>> for QueryNormalizer<'cx, 'tcx>
}
return Err(NoSolution);
}
- let InferOk { value: result, obligations } =
- self.infcx.instantiate_query_response_and_region_obligations(
+ let InferOk { value: result, obligations } = infcx
+ .instantiate_query_response_and_region_obligations(
self.cause,
self.param_env,
&orig_values,
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
index e6db96c9e..01d7a1e79 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs
@@ -1,8 +1,13 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
-use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use crate::traits::ObligationCtxt;
+use rustc_hir::def_id::{DefId, CRATE_DEF_ID};
+use rustc_infer::traits::Obligation;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::{ObligationCause, ObligationCauseCode};
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, UserSelfTy, UserSubsts, UserType};
pub use rustc_middle::traits::query::type_op::AscribeUserType;
+use rustc_span::{Span, DUMMY_SP};
impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
type QueryResponse = ();
@@ -17,7 +22,119 @@ impl<'tcx> super::QueryTypeOp<'tcx> for AscribeUserType<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
tcx.type_op_ascribe_user_type(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ type_op_ascribe_user_type_with_span(ocx, key, None)
+ }
+}
+
+/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
+/// this query can be re-run to better track the span of the obligation cause, and improve the error
+/// message. Do not call directly unless you're in that very specific context.
+pub fn type_op_ascribe_user_type_with_span<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
+ span: Option<Span>,
+) -> Result<(), NoSolution> {
+ let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
+ debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
+ let span = span.unwrap_or(DUMMY_SP);
+ match user_ty {
+ UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
+ UserType::TypeOf(def_id, user_substs) => {
+ relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
+ }
+ };
+ Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_ty<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+ mir_ty: Ty<'tcx>,
+ user_ty: Ty<'tcx>,
+) -> Result<(), NoSolution> {
+ let cause = ObligationCause::dummy_with_span(span);
+ let user_ty = ocx.normalize(&cause, param_env, user_ty);
+ ocx.eq(&cause, param_env, mir_ty, user_ty)?;
+
+ // FIXME(#104764): We should check well-formedness before normalization.
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
+ ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
+ Ok(())
+}
+
+#[instrument(level = "debug", skip(ocx, param_env, span))]
+fn relate_mir_and_user_substs<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ span: Span,
+ mir_ty: Ty<'tcx>,
+ def_id: DefId,
+ user_substs: UserSubsts<'tcx>,
+) -> Result<(), NoSolution> {
+ let param_env = param_env.without_const();
+ let UserSubsts { user_self_ty, substs } = user_substs;
+ let tcx = ocx.infcx.tcx;
+ let cause = ObligationCause::dummy_with_span(span);
+
+ let ty = tcx.type_of(def_id).subst(tcx, substs);
+ let ty = ocx.normalize(&cause, param_env, ty);
+ debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
+
+ ocx.eq(&cause, param_env, mir_ty, ty)?;
+
+ // Prove the predicates coming along with `def_id`.
+ //
+ // Also, normalize the `instantiated_predicates`
+ // because otherwise we wind up with duplicate "type
+ // outlives" error messages.
+ let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
+
+ debug!(?instantiated_predicates);
+ for (instantiated_predicate, predicate_span) in instantiated_predicates {
+ let span = if span == DUMMY_SP { predicate_span } else { span };
+ let cause = ObligationCause::new(
+ span,
+ CRATE_DEF_ID,
+ ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
+ );
+ let instantiated_predicate =
+ ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
+
+ ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
+ }
+
+ if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
+ let self_ty = ocx.normalize(&cause, param_env, self_ty);
+ let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs);
+ let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
+
+ ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
+ ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
+ }
+
+ // In addition to proving the predicates, we have to
+ // prove that `ty` is well-formed -- this is because
+ // the WF of `ty` is predicated on the substs being
+ // well-formed, and we haven't proven *that*. We don't
+ // want to prove the WF of types from `substs` directly because they
+ // haven't been normalized.
+ //
+ // FIXME(nmatsakis): Well, perhaps we should normalize
+ // them? This would only be relevant if some input
+ // type were ill-formed but did not appear in `ty`,
+ // which...could happen with normalization...
+ let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
+ ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
+ Ok(())
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
index 8f1b05c11..6d8d2103f 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs
@@ -1,32 +1,32 @@
use crate::infer::canonical::query_response;
-use crate::infer::{InferCtxt, InferOk};
+use crate::infer::InferCtxt;
use crate::traits::query::type_op::TypeOpOutput;
-use crate::traits::query::Fallible;
use crate::traits::ObligationCtxt;
+use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::region_constraints::RegionConstraintData;
+use rustc_middle::traits::query::NoSolution;
use rustc_span::source_map::DUMMY_SP;
+use rustc_span::Span;
use std::fmt;
-pub struct CustomTypeOp<F, G> {
+pub struct CustomTypeOp<F> {
closure: F,
- description: G,
+ description: &'static str,
}
-impl<F, G> CustomTypeOp<F, G> {
- pub fn new<'tcx, R>(closure: F, description: G) -> Self
+impl<F> CustomTypeOp<F> {
+ pub fn new<'tcx, R>(closure: F, description: &'static str) -> Self
where
- F: FnOnce(&InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
- G: Fn() -> String,
+ F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
{
CustomTypeOp { closure, description }
}
}
-impl<'tcx, F, R: fmt::Debug, G> super::TypeOp<'tcx> for CustomTypeOp<F, G>
+impl<'tcx, F, R: fmt::Debug> super::TypeOp<'tcx> for CustomTypeOp<F>
where
- F: for<'a, 'cx> FnOnce(&'a InferCtxt<'tcx>) -> Fallible<InferOk<'tcx, R>>,
- G: Fn() -> String,
+ F: FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
{
type Output = R;
/// We can't do any custom error reporting for `CustomTypeOp`, so
@@ -36,21 +36,22 @@ where
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
- fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ fn fully_perform(
+ self,
+ infcx: &InferCtxt<'tcx>,
+ span: Span,
+ ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
if cfg!(debug_assertions) {
info!("fully_perform({:?})", self);
}
- Ok(scrape_region_constraints(infcx, || (self.closure)(infcx))?.0)
+ Ok(scrape_region_constraints(infcx, self.closure, self.description, span)?.0)
}
}
-impl<F, G> fmt::Debug for CustomTypeOp<F, G>
-where
- G: Fn() -> String,
-{
+impl<F> fmt::Debug for CustomTypeOp<F> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "{}", (self.description)())
+ self.description.fmt(f)
}
}
@@ -58,8 +59,10 @@ where
/// constraints that result, creating query-region-constraints.
pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
infcx: &InferCtxt<'tcx>,
- op: impl FnOnce() -> Fallible<InferOk<'tcx, R>>,
-) -> Fallible<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>)> {
+ op: impl FnOnce(&ObligationCtxt<'_, 'tcx>) -> Result<R, NoSolution>,
+ name: &'static str,
+ span: Span,
+) -> Result<(TypeOpOutput<'tcx, Op>, RegionConstraintData<'tcx>), ErrorGuaranteed> {
// During NLL, we expect that nobody will register region
// obligations **except** as part of a custom type op (and, at the
// end of each custom type op, we scrape out the region
@@ -72,16 +75,21 @@ pub fn scrape_region_constraints<'tcx, Op: super::TypeOp<'tcx, Output = R>, R>(
pre_obligations,
);
- let InferOk { value, obligations } = infcx.commit_if_ok(|_| op())?;
- let ocx = ObligationCtxt::new(infcx);
- ocx.register_obligations(obligations);
- let errors = ocx.select_all_or_error();
- if !errors.is_empty() {
- infcx.tcx.sess.diagnostic().delay_span_bug(
- DUMMY_SP,
- &format!("errors selecting obligation during MIR typeck: {:?}", errors),
- );
- }
+ let value = infcx.commit_if_ok(|_| {
+ let ocx = ObligationCtxt::new_in_snapshot(infcx);
+ let value = op(&ocx).map_err(|_| {
+ infcx.tcx.sess.delay_span_bug(span, format!("error performing operation: {name}"))
+ })?;
+ let errors = ocx.select_all_or_error();
+ if errors.is_empty() {
+ Ok(value)
+ } else {
+ Err(infcx.tcx.sess.delay_span_bug(
+ DUMMY_SP,
+ format!("errors selecting obligation during MIR typeck: {:?}", errors),
+ ))
+ }
+ })?;
let region_obligations = infcx.take_registered_region_obligations();
let region_constraint_data = infcx.take_and_reset_region_constraints();
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
index 8c9b9610c..f65893088 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs
@@ -1,5 +1,7 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
pub use rustc_middle::traits::query::type_op::Eq;
@@ -17,7 +19,15 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Eq<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
tcx.type_op_eq(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ ocx.eq(&ObligationCause::dummy(), key.param_env, key.value.a, key.value.b)?;
+ Ok(())
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
index 18d7c9b19..9989fc9c4 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs
@@ -1,7 +1,15 @@
-use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::query::NoSolution;
+use crate::traits::wf;
+use crate::traits::ObligationCtxt;
+
+use rustc_infer::infer::canonical::Canonical;
+use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_infer::traits::query::OutlivesBound;
-use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt};
+use rustc_middle::infer::canonical::CanonicalQueryResponse;
+use rustc_middle::ty::{self, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
+use rustc_span::def_id::CRATE_DEF_ID;
+use rustc_span::source_map::DUMMY_SP;
+use smallvec::{smallvec, SmallVec};
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
pub struct ImpliedOutlivesBounds<'tcx> {
@@ -28,7 +36,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
// FIXME this `unchecked_map` is only necessary because the
// query is defined as taking a `ParamEnvAnd<Ty>`; it should
// take an `ImpliedOutlivesBounds` instead
@@ -39,4 +47,169 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ImpliedOutlivesBounds<'tcx> {
tcx.implied_outlives_bounds(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ compute_implied_outlives_bounds_inner(ocx, key.param_env, key.value.ty)
+ }
+}
+
+pub fn compute_implied_outlives_bounds_inner<'tcx>(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ ty: Ty<'tcx>,
+) -> Result<Vec<OutlivesBound<'tcx>>, NoSolution> {
+ let tcx = ocx.infcx.tcx;
+
+ // Sometimes when we ask what it takes for T: WF, we get back that
+ // U: WF is required; in that case, we push U onto this stack and
+ // process it next. Because the resulting predicates aren't always
+ // guaranteed to be a subset of the original type, so we need to store the
+ // WF args we've computed in a set.
+ let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
+ let mut wf_args = vec![ty.into()];
+
+ let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
+ vec![];
+
+ while let Some(arg) = wf_args.pop() {
+ if !checked_wf_args.insert(arg) {
+ continue;
+ }
+
+ // Compute the obligations for `arg` to be well-formed. If `arg` is
+ // an unresolved inference variable, just substituted an empty set
+ // -- because the return type here is going to be things we *add*
+ // to the environment, it's always ok for this set to be smaller
+ // than the ultimate set. (Note: normally there won't be
+ // unresolved inference variables here anyway, but there might be
+ // during typeck under some circumstances.)
+ //
+ // FIXME(@lcnr): It's not really "always fine", having fewer implied
+ // bounds can be backward incompatible, e.g. #101951 was caused by
+ // us not dealing with inference vars in `TypeOutlives` predicates.
+ let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
+ .unwrap_or_default();
+
+ for obligation in obligations {
+ debug!(?obligation);
+ assert!(!obligation.has_escaping_bound_vars());
+
+ // While these predicates should all be implied by other parts of
+ // the program, they are still relevant as they may constrain
+ // inference variables, which is necessary to add the correct
+ // implied bounds in some cases, mostly when dealing with projections.
+ //
+ // Another important point here: we only register `Projection`
+ // predicates, since otherwise we might register outlives
+ // predicates containing inference variables, and we don't
+ // learn anything new from those.
+ if obligation.predicate.has_non_region_infer() {
+ match obligation.predicate.kind().skip_binder() {
+ ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::AliasRelate(..) => {
+ ocx.register_obligation(obligation.clone());
+ }
+ _ => {}
+ }
+ }
+
+ let pred = match obligation.predicate.kind().no_bound_vars() {
+ None => continue,
+ Some(pred) => pred,
+ };
+ match pred {
+ ty::PredicateKind::Clause(ty::Clause::Trait(..))
+ // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
+ // if we ever support that
+ | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::Clause(ty::Clause::Projection(..))
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::ObjectSafe(..)
+ | ty::PredicateKind::ConstEvaluatable(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
+ | ty::PredicateKind::AliasRelate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
+
+ // We need to search through *all* WellFormed predicates
+ ty::PredicateKind::WellFormed(arg) => {
+ wf_args.push(arg);
+ }
+
+ // We need to register region relationships
+ ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
+ r_a,
+ r_b,
+ ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
+
+ ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
+ ty_a,
+ r_b,
+ ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
+ }
+ }
+ }
+
+ // This call to `select_all_or_error` is necessary to constrain inference variables, which we
+ // use further down when computing the implied bounds.
+ match ocx.select_all_or_error().as_slice() {
+ [] => (),
+ _ => return Err(NoSolution),
+ }
+
+ // We lazily compute the outlives components as
+ // `select_all_or_error` constrains inference variables.
+ let implied_bounds = outlives_bounds
+ .into_iter()
+ .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
+ ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
+ ty::GenericArgKind::Type(ty_a) => {
+ let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
+ let mut components = smallvec![];
+ push_outlives_components(tcx, ty_a, &mut components);
+ implied_bounds_from_components(r_b, components)
+ }
+ ty::GenericArgKind::Const(_) => unreachable!(),
+ })
+ .collect();
+
+ Ok(implied_bounds)
+}
+
+/// When we have an implied bound that `T: 'a`, we can further break
+/// this down to determine what relationships would have to hold for
+/// `T: 'a` to hold. We get to assume that the caller has validated
+/// those relationships.
+fn implied_bounds_from_components<'tcx>(
+ sub_region: ty::Region<'tcx>,
+ sup_components: SmallVec<[Component<'tcx>; 4]>,
+) -> Vec<OutlivesBound<'tcx>> {
+ sup_components
+ .into_iter()
+ .filter_map(|component| {
+ match component {
+ Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
+ Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
+ Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
+ Component::EscapingAlias(_) =>
+ // If the projection has escaping regions, don't
+ // try to infer any implied bounds even for its
+ // free components. This is conservative, because
+ // the caller will still have to prove that those
+ // free components outlive `sub_region`. But the
+ // idea is that the WAY that the caller proves
+ // that may change in the future and we want to
+ // give ourselves room to get smarter here.
+ {
+ None
+ }
+ Component::UnresolvedInferenceVariable(..) => None,
+ }
+ })
+ .collect()
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
index 9e8bc8bce..642fdec2d 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs
@@ -2,13 +2,14 @@ use crate::infer::canonical::{
Canonical, CanonicalQueryResponse, OriginalQueryValues, QueryRegionConstraints,
};
use crate::infer::{InferCtxt, InferOk};
-use crate::traits::query::Fallible;
-use crate::traits::ObligationCause;
+use crate::traits::{ObligationCause, ObligationCtxt};
+use rustc_errors::ErrorGuaranteed;
use rustc_infer::infer::canonical::Certainty;
-use rustc_infer::traits::query::NoSolution;
use rustc_infer::traits::PredicateObligations;
+use rustc_middle::traits::query::NoSolution;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
+use rustc_span::Span;
use std::fmt;
pub mod ascribe_user_type;
@@ -22,6 +23,8 @@ pub mod subtype;
pub use rustc_middle::traits::query::type_op::*;
+use self::custom::scrape_region_constraints;
+
/// "Type ops" are used in NLL to perform some particular action and
/// extract out the resulting region constraints (or an error if it
/// cannot be completed).
@@ -32,7 +35,11 @@ pub trait TypeOp<'tcx>: Sized + fmt::Debug {
/// Processes the operation and all resulting obligations,
/// returning the final result along with any region constraints
/// (they will be given over to the NLL region solver).
- fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>>;
+ fn fully_perform(
+ self,
+ infcx: &InferCtxt<'tcx>,
+ span: Span,
+ ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed>;
}
/// The output from performing a type op
@@ -74,18 +81,32 @@ pub trait QueryTypeOp<'tcx>: fmt::Debug + Copy + TypeFoldable<TyCtxt<'tcx>> + 't
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>>;
+ ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution>;
+
+ /// In the new trait solver, we already do caching in the solver itself,
+ /// so there's no need to canonicalize and cache via the query system.
+ /// Additionally, even if we were to canonicalize, we'd still need to
+ /// make sure to feed it predefined opaque types and the defining anchor
+ /// and that would require duplicating all of the tcx queries. Instead,
+ /// just perform these ops locally.
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution>;
fn fully_perform_into(
query_key: ParamEnvAnd<'tcx, Self>,
infcx: &InferCtxt<'tcx>,
output_query_region_constraints: &mut QueryRegionConstraints<'tcx>,
- ) -> Fallible<(
- Self::QueryResponse,
- Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
- PredicateObligations<'tcx>,
- Certainty,
- )> {
+ ) -> Result<
+ (
+ Self::QueryResponse,
+ Option<Canonical<'tcx, ParamEnvAnd<'tcx, Self>>>,
+ PredicateObligations<'tcx>,
+ Certainty,
+ ),
+ NoSolution,
+ > {
if let Some(result) = QueryTypeOp::try_fast_path(infcx.tcx, &query_key) {
return Ok((result, None, vec![], Certainty::Proven));
}
@@ -120,10 +141,26 @@ where
type Output = Q::QueryResponse;
type ErrorInfo = Canonical<'tcx, ParamEnvAnd<'tcx, Q>>;
- fn fully_perform(self, infcx: &InferCtxt<'tcx>) -> Fallible<TypeOpOutput<'tcx, Self>> {
+ fn fully_perform(
+ self,
+ infcx: &InferCtxt<'tcx>,
+ span: Span,
+ ) -> Result<TypeOpOutput<'tcx, Self>, ErrorGuaranteed> {
+ if infcx.tcx.trait_solver_next() {
+ return Ok(scrape_region_constraints(
+ infcx,
+ |ocx| QueryTypeOp::perform_locally_in_new_solver(ocx, self),
+ "query type op",
+ span,
+ )?
+ .0);
+ }
+
let mut region_constraints = QueryRegionConstraints::default();
let (output, error_info, mut obligations, _) =
- Q::fully_perform_into(self, infcx, &mut region_constraints)?;
+ Q::fully_perform_into(self, infcx, &mut region_constraints).map_err(|_| {
+ infcx.tcx.sess.delay_span_bug(span, format!("error performing {self:?}"))
+ })?;
// Typically, instantiating NLL query results does not
// create obligations. However, in some cases there
@@ -151,7 +188,10 @@ where
}
}
if !progress {
- return Err(NoSolution);
+ return Err(infcx.tcx.sess.delay_span_bug(
+ span,
+ format!("ambiguity processing {obligations:?} from {self:?}"),
+ ));
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
index 5b216c076..57ca14aa4 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs
@@ -1,5 +1,7 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::fold::TypeFoldable;
use rustc_middle::ty::{self, Lift, ParamEnvAnd, Ty, TyCtxt, TypeVisitableExt};
use std::fmt;
@@ -19,23 +21,31 @@ where
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
T::type_op_method(tcx, canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ // FIXME(-Ztrait-solver=next): shouldn't be using old normalizer
+ Ok(ocx.normalize(&ObligationCause::dummy(), key.param_env, key.value.value))
+ }
}
pub trait Normalizable<'tcx>: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx> + Copy {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self>>;
+ ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution>;
}
impl<'tcx> Normalizable<'tcx> for Ty<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
tcx.type_op_normalize_ty(canonicalized)
}
}
@@ -44,7 +54,7 @@ impl<'tcx> Normalizable<'tcx> for ty::Predicate<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
tcx.type_op_normalize_predicate(canonicalized)
}
}
@@ -53,7 +63,7 @@ impl<'tcx> Normalizable<'tcx> for ty::PolyFnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
tcx.type_op_normalize_poly_fn_sig(canonicalized)
}
}
@@ -62,7 +72,7 @@ impl<'tcx> Normalizable<'tcx> for ty::FnSig<'tcx> {
fn type_op_method(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Normalize<Self>>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self>, NoSolution> {
tcx.type_op_normalize_fn_sig(canonicalized)
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
index 21ef4e24f..988942633 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs
@@ -1,6 +1,9 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::dropck_outlives::{trivial_dropck_outlives, DropckOutlivesResult};
-use crate::traits::query::Fallible;
+use crate::traits::query::dropck_outlives::{
+ compute_dropck_outlives_inner, trivial_dropck_outlives,
+};
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::{DropckOutlivesResult, NoSolution};
use rustc_middle::ty::{ParamEnvAnd, Ty, TyCtxt};
#[derive(Copy, Clone, Debug, HashStable, TypeFoldable, TypeVisitable, Lift)]
@@ -27,7 +30,7 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, Self::QueryResponse>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, Self::QueryResponse>, NoSolution> {
// Subtle: note that we are not invoking
// `infcx.at(...).dropck_outlives(...)` here, but rather the
// underlying `dropck_outlives` query. This same underlying
@@ -48,4 +51,11 @@ impl<'tcx> super::QueryTypeOp<'tcx> for DropckOutlives<'tcx> {
tcx.dropck_outlives(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ compute_dropck_outlives_inner(ocx, key.param_env.and(key.value.dropped_ty))
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
index b63da28e2..47850bc33 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs
@@ -1,5 +1,8 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_infer::traits::Obligation;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt};
pub use rustc_middle::traits::query::type_op::ProvePredicate;
@@ -32,14 +35,21 @@ impl<'tcx> super::QueryTypeOp<'tcx> for ProvePredicate<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
- mut canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
- match canonicalized.value.value.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Trait(pred)) => {
- canonicalized.value.param_env.remap_constness_with(pred.constness);
- }
- _ => canonicalized.value.param_env = canonicalized.value.param_env.without_const(),
- }
+ canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
+ ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
tcx.type_op_prove_predicate(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ ocx.register_obligation(Obligation::new(
+ ocx.infcx.tcx,
+ ObligationCause::dummy(),
+ key.param_env,
+ key.value.predicate,
+ ));
+ Ok(())
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
index c51292eba..10976d5cd 100644
--- a/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
+++ b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs
@@ -1,5 +1,7 @@
use crate::infer::canonical::{Canonical, CanonicalQueryResponse};
-use crate::traits::query::Fallible;
+use crate::traits::ObligationCtxt;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::ObligationCause;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
pub use rustc_middle::traits::query::type_op::Subtype;
@@ -14,7 +16,15 @@ impl<'tcx> super::QueryTypeOp<'tcx> for Subtype<'tcx> {
fn perform_query(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Self>>,
- ) -> Fallible<CanonicalQueryResponse<'tcx, ()>> {
+ ) -> Result<CanonicalQueryResponse<'tcx, ()>, NoSolution> {
tcx.type_op_subtype(canonicalized)
}
+
+ fn perform_locally_in_new_solver(
+ ocx: &ObligationCtxt<'_, 'tcx>,
+ key: ParamEnvAnd<'tcx, Self>,
+ ) -> Result<Self::QueryResponse, NoSolution> {
+ ocx.sub(&ObligationCause::dummy(), key.param_env, key.value.sub, key.value.sup)?;
+ Ok(())
+ }
}
diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
index 1f5bbc178..8bc82b9f5 100644
--- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs
@@ -11,7 +11,7 @@ use hir::LangItem;
use rustc_hir as hir;
use rustc_infer::traits::ObligationCause;
use rustc_infer::traits::{Obligation, SelectionError, TraitObligation};
-use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams, TreatProjections};
+use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams};
use rustc_middle::ty::{self, Ty, TypeVisitableExt};
use crate::traits;
@@ -57,6 +57,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if obligation.polarity() == ty::ImplPolarity::Negative {
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
+ self.assemble_candidates_from_caller_bounds(stack, &mut candidates)?;
} else {
self.assemble_candidates_for_trait_alias(obligation, &mut candidates);
@@ -142,7 +143,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Before we go into the whole placeholder thing, just
// quickly check if the self-type is a projection at all.
match obligation.predicate.skip_binder().trait_ref.self_ty().kind() {
- ty::Alias(..) => {}
+ // Excluding IATs here as they don't have meaningful item bounds.
+ ty::Alias(ty::Projection | ty::Opaque, _) => {}
ty::Infer(ty::TyVar(_)) => {
span_bug!(
obligation.cause.span,
@@ -187,6 +189,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Keep only those bounds which may apply, and propagate overflow if it occurs.
for bound in matching_bounds {
+ if bound.skip_binder().polarity != stack.obligation.predicate.skip_binder().polarity {
+ continue;
+ }
+
// FIXME(oli-obk): it is suspicious that we are dropping the constness and
// polarity here.
let wc = self.where_clause_may_apply(stack, bound.map_bound(|t| t.trait_ref))?;
@@ -454,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.param_env,
self.tcx().mk_predicate(obligation.predicate.map_bound(|mut pred| {
pred.trait_ref =
- self.tcx().mk_trait_ref(fn_ptr_trait, [pred.trait_ref.self_ty()]);
+ ty::TraitRef::new(self.tcx(), fn_ptr_trait, [pred.trait_ref.self_ty()]);
ty::PredicateKind::Clause(ty::Clause::Trait(pred))
})),
);
@@ -493,7 +499,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// this trait and type.
}
ty::Param(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Placeholder(..)
| ty::Bound(..) => {
// In these cases, we don't know what the actual
@@ -629,7 +635,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
// <ty as Deref>
- let trait_ref = tcx.mk_trait_ref(tcx.lang_items().deref_trait()?, [ty]);
+ let trait_ref = ty::TraitRef::new(tcx, tcx.lang_items().deref_trait()?, [ty]);
let obligation =
traits::Obligation::new(tcx, cause.clone(), param_env, ty::Binder::dummy(trait_ref));
@@ -775,7 +781,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
- if obligation.has_non_region_param() {
+ if obligation.predicate.has_non_region_param() {
return;
}
@@ -875,12 +881,24 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
ty::Adt(..) => {
- // Find a custom `impl Drop` impl, if it exists
- let relevant_impl = self.tcx().find_map_relevant_impl(
+ let mut relevant_impl = None;
+ self.tcx().for_each_relevant_impl(
self.tcx().require_lang_item(LangItem::Drop, None),
obligation.predicate.skip_binder().trait_ref.self_ty(),
- TreatProjections::ForLookup,
- Some,
+ |impl_def_id| {
+ if let Some(old_impl_def_id) = relevant_impl {
+ self.tcx()
+ .sess
+ .struct_span_err(
+ self.tcx().def_span(impl_def_id),
+ "multiple drop impls found",
+ )
+ .span_note(self.tcx().def_span(old_impl_def_id), "other impl here")
+ .delay_as_bug();
+ }
+
+ relevant_impl = Some(impl_def_id);
+ },
);
if let Some(impl_def_id) = relevant_impl {
@@ -949,16 +967,18 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) {
// The regions of a type don't affect the size of the type
let tcx = self.tcx();
- let self_ty =
- tcx.erase_regions(tcx.erase_late_bound_regions(obligation.predicate.self_ty()));
-
+ let self_ty = tcx.erase_late_bound_regions(obligation.predicate.self_ty());
+ // We should erase regions from both the param-env and type, since both
+ // may have infer regions. Specifically, after canonicalizing and instantiating,
+ // early bound regions turn into region vars in both the new and old solver.
+ let key = tcx.erase_regions(obligation.param_env.and(self_ty));
// But if there are inference variables, we have to wait until it's resolved.
- if self_ty.has_non_region_infer() {
+ if key.has_non_region_infer() {
candidates.ambiguous = true;
return;
}
- if let Ok(layout) = tcx.layout_of(obligation.param_env.and(self_ty))
+ if let Ok(layout) = tcx.layout_of(key)
&& layout.layout.is_pointer_like(&tcx.data_layout)
{
candidates.vec.push(BuiltinCandidate { has_nested: false });
diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
index 88121f865..0d9f55d4c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs
@@ -10,6 +10,7 @@ use rustc_data_structures::stack::ensure_sufficient_stack;
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::LateBoundRegionConversionTime::HigherRankedType;
use rustc_infer::infer::{DefineOpaqueTypes, InferOk};
+use rustc_middle::traits::SelectionOutputTypeParameterMismatch;
use rustc_middle::ty::{
self, Binder, GenericParamDefKind, InternalSubsts, SubstsRef, ToPolyTraitRef, ToPredicate,
TraitRef, Ty, TyCtxt, TypeVisitableExt,
@@ -28,9 +29,9 @@ use crate::traits::{
ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData,
ImplSourceConstDestructData, ImplSourceFnPointerData, ImplSourceFutureData,
ImplSourceGeneratorData, ImplSourceObjectData, ImplSourceTraitAliasData,
- ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation,
- Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection,
- SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented,
+ ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, Obligation,
+ ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, SelectionError,
+ TraitNotObjectSafe, TraitObligation, Unimplemented,
};
use super::BuiltinImplConditions;
@@ -161,7 +162,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let placeholder_self_ty = placeholder_trait_predicate.self_ty();
let placeholder_trait_predicate = ty::Binder::dummy(placeholder_trait_predicate);
let (def_id, substs) = match *placeholder_self_ty.kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
+ // Excluding IATs here as they don't have meaningful item bounds.
+ ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+ (def_id, substs)
+ }
_ => bug!("projection candidate for unexpected type: {:?}", placeholder_self_ty),
};
@@ -281,33 +285,35 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<ImplSourceBuiltinData<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
debug!(?obligation, "confirm_transmutability_candidate");
- let predicate = obligation.predicate;
-
- let type_at = |i| predicate.map_bound(|p| p.trait_ref.substs.type_at(i));
- let const_at = |i| predicate.skip_binder().trait_ref.substs.const_at(i);
-
- let src_and_dst = predicate.map_bound(|p| rustc_transmute::Types {
- dst: p.trait_ref.substs.type_at(0),
- src: p.trait_ref.substs.type_at(1),
- });
-
- let scope = type_at(2).skip_binder();
-
- let Some(assume) =
- rustc_transmute::Assume::from_const(self.infcx.tcx, obligation.param_env, const_at(3)) else {
- return Err(Unimplemented);
- };
+ // We erase regions here because transmutability calls layout queries,
+ // which does not handle inference regions and doesn't particularly
+ // care about other regions. Erasing late-bound regions is equivalent
+ // to instantiating the binder with placeholders then erasing those
+ // placeholder regions.
+ let predicate =
+ self.tcx().erase_regions(self.tcx().erase_late_bound_regions(obligation.predicate));
- let cause = obligation.cause.clone();
+ let Some(assume) = rustc_transmute::Assume::from_const(
+ self.infcx.tcx,
+ obligation.param_env,
+ predicate.trait_ref.substs.const_at(3)
+ ) else {
+ return Err(Unimplemented);
+ };
let mut transmute_env = rustc_transmute::TransmuteTypeEnv::new(self.infcx);
-
- let maybe_transmutable = transmute_env.is_transmutable(cause, src_and_dst, scope, assume);
-
- use rustc_transmute::Answer;
+ let maybe_transmutable = transmute_env.is_transmutable(
+ obligation.cause.clone(),
+ rustc_transmute::Types {
+ dst: predicate.trait_ref.substs.type_at(0),
+ src: predicate.trait_ref.substs.type_at(1),
+ },
+ predicate.trait_ref.substs.type_at(2),
+ assume,
+ );
match maybe_transmutable {
- Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
+ rustc_transmute::Answer::Yes => Ok(ImplSourceBuiltinData { nested: vec![] }),
_ => Err(Unimplemented),
}
}
@@ -650,8 +656,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
output_ty,
&mut nested,
);
- let tr =
- ty::Binder::dummy(self.tcx().at(cause.span).mk_trait_ref(LangItem::Sized, [output_ty]));
+ let tr = ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [output_ty]);
nested.push(Obligation::new(self.infcx.tcx, cause, obligation.param_env, tr));
Ok(ImplSourceFnPointerData { fn_ty: self_ty, nested })
@@ -816,7 +821,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
fn confirm_poly_trait_refs(
&mut self,
obligation: &TraitObligation<'tcx>,
- expected_trait_ref: ty::PolyTraitRef<'tcx>,
+ self_ty_trait_ref: ty::PolyTraitRef<'tcx>,
) -> Result<Vec<PredicateObligation<'tcx>>, SelectionError<'tcx>> {
let obligation_trait_ref = obligation.predicate.to_poly_trait_ref();
// Normalize the obligation and expected trait refs together, because why not
@@ -827,7 +832,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation.param_env,
obligation.cause.clone(),
obligation.recursion_depth + 1,
- (obligation_trait_ref, expected_trait_ref),
+ (obligation_trait_ref, self_ty_trait_ref),
)
});
@@ -839,7 +844,13 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligations.extend(nested);
obligations
})
- .map_err(|e| OutputTypeParameterMismatch(expected_trait_ref, obligation_trait_ref, e))
+ .map_err(|terr| {
+ OutputTypeParameterMismatch(Box::new(SelectionOutputTypeParameterMismatch {
+ expected_trait_ref: obligation_trait_ref,
+ found_trait_ref: expected_trait_ref,
+ terr,
+ }))
+ })
}
fn confirm_trait_upcasting_unsize_candidate(
@@ -903,16 +914,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map_err(|_| Unimplemented)?;
nested.extend(obligations);
- // Register one obligation for 'a: 'b.
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
- cause,
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
@@ -1003,15 +1008,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Register one obligation for 'a: 'b.
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
let outlives = ty::OutlivesPredicate(r_a, r_b);
nested.push(Obligation::with_depth(
tcx,
- cause,
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
obligation.predicate.rebind(outlives),
@@ -1025,16 +1025,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return Err(TraitNotObjectSafe(did));
}
- let cause = ObligationCause::new(
- obligation.cause.span,
- obligation.cause.body_id,
- ObjectCastObligation(source, target),
- );
-
let predicate_to_obligation = |predicate| {
Obligation::with_depth(
tcx,
- cause.clone(),
+ obligation.cause.clone(),
obligation.recursion_depth + 1,
obligation.param_env,
predicate,
@@ -1054,8 +1048,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
);
// We can only make objects from sized types.
- let tr =
- ty::Binder::dummy(tcx.at(cause.span).mk_trait_ref(LangItem::Sized, [source]));
+ let tr = ty::TraitRef::from_lang_item(
+ tcx,
+ LangItem::Sized,
+ obligation.cause.span,
+ [source],
+ );
nested.push(predicate_to_obligation(tr.without_const().to_predicate(tcx)));
// If the type is `Foo + 'a`, ensure that the type
@@ -1125,7 +1123,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// Construct the nested `TailField<T>: Unsize<TailField<U>>` predicate.
let tail_unsize_obligation = obligation.with(
tcx,
- tcx.mk_trait_ref(obligation.predicate.def_id(), [source_tail, target_tail]),
+ ty::TraitRef::new(
+ tcx,
+ obligation.predicate.def_id(),
+ [source_tail, target_tail],
+ ),
);
nested.push(tail_unsize_obligation);
}
@@ -1150,8 +1152,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
nested.extend(obligations);
// Add a nested `T: Unsize<U>` predicate.
- let last_unsize_obligation = obligation
- .with(tcx, tcx.mk_trait_ref(obligation.predicate.def_id(), [a_last, b_last]));
+ let last_unsize_obligation = obligation.with(
+ tcx,
+ ty::TraitRef::new(tcx, obligation.predicate.def_id(), [a_last, b_last]),
+ );
nested.push(last_unsize_obligation);
}
@@ -1268,17 +1272,19 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// If we have a projection type, make sure to normalize it so we replace it
// with a fresh infer variable
- ty::Alias(ty::Projection, ..) => {
+ ty::Alias(ty::Projection | ty::Inherent, ..) => {
let predicate = normalize_with_depth_to(
self,
obligation.param_env,
cause.clone(),
obligation.recursion_depth + 1,
self_ty.rebind(ty::TraitPredicate {
- trait_ref: self
- .tcx()
- .at(cause.span)
- .mk_trait_ref(LangItem::Destruct, [nested_ty]),
+ trait_ref: ty::TraitRef::from_lang_item(
+ self.tcx(),
+ LangItem::Destruct,
+ cause.span,
+ [nested_ty],
+ ),
constness: ty::BoundConstness::ConstIfConst,
polarity: ty::ImplPolarity::Positive,
}),
@@ -1299,10 +1305,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// or it's an ADT (and we need to check for a custom impl during selection)
_ => {
let predicate = self_ty.rebind(ty::TraitPredicate {
- trait_ref: self
- .tcx()
- .at(cause.span)
- .mk_trait_ref(LangItem::Destruct, [nested_ty]),
+ trait_ref: ty::TraitRef::from_lang_item(
+ self.tcx(),
+ LangItem::Destruct,
+ cause.span,
+ [nested_ty],
+ ),
constness: ty::BoundConstness::ConstIfConst,
polarity: ty::ImplPolarity::Positive,
});
diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs
index 6bb53418b..3baf1c97c 100644
--- a/compiler/rustc_trait_selection/src/traits/select/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs
@@ -67,7 +67,7 @@ impl IntercrateAmbiguityCause {
/// Emits notes when the overlap is caused by complex intercrate ambiguities.
/// See #23980 for details.
pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) {
- err.note(&self.intercrate_ambiguity_hint());
+ err.note(self.intercrate_ambiguity_hint());
}
pub fn intercrate_ambiguity_hint(&self) -> String {
@@ -449,7 +449,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
debug!(?stack, ?candidates, "winnowed to {} candidates", candidates.len());
- let needs_infer = stack.obligation.predicate.has_non_region_infer();
+ let has_non_region_infer = stack.obligation.predicate.has_non_region_infer();
// If there are STILL multiple candidates, we can further
// reduce the list by dropping duplicates -- including
@@ -461,7 +461,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.candidate_should_be_dropped_in_favor_of(
&candidates[i],
&candidates[j],
- needs_infer,
+ has_non_region_infer,
) == DropVictim::Yes
});
if should_drop_i {
@@ -537,14 +537,22 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &PredicateObligation<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
self.evaluation_probe(|this| {
- if this.tcx().trait_solver_next() {
- this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])
+ let goal =
+ this.infcx.resolve_vars_if_possible((obligation.predicate, obligation.param_env));
+ let mut result = if this.tcx().trait_solver_next() {
+ this.evaluate_predicates_recursively_in_new_solver([obligation.clone()])?
} else {
this.evaluate_predicate_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
obligation.clone(),
- )
+ )?
+ };
+ // If the predicate has done any inference, then downgrade the
+ // result to ambiguous.
+ if this.infcx.shallow_resolve(goal) != goal {
+ result = result.max(EvaluatedToAmbig);
}
+ Ok(result)
})
}
@@ -888,7 +896,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let c1 = tcx.expand_abstract_consts(c1);
let c2 = tcx.expand_abstract_consts(c2);
debug!(
- "evalaute_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}",
+ "evaluate_predicate_recursively: equating consts:\nc1= {:?}\nc2= {:?}",
c1, c2
);
@@ -896,8 +904,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
use ty::ConstKind::Unevaluated;
match (c1.kind(), c2.kind()) {
(Unevaluated(a), Unevaluated(b))
- if a.def.did == b.def.did
- && tcx.def_kind(a.def.did) == DefKind::AssocConst =>
+ if a.def == b.def && tcx.def_kind(a.def) == DefKind::AssocConst =>
{
if let Ok(InferOk { obligations, value: () }) = self
.infcx
@@ -1001,7 +1008,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
) -> Result<EvaluationResult, OverflowError> {
if !self.is_intercrate()
&& obligation.is_global()
- && obligation.param_env.caller_bounds().iter().all(|bound| bound.needs_subst())
+ && obligation.param_env.caller_bounds().iter().all(|bound| bound.has_param())
{
// If a param env has no global bounds, global obligations do not
// depend on its particular value in order to work, so we can clear
@@ -1331,7 +1338,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
if self.can_use_global_caches(param_env) {
- if !trait_pred.needs_infer() {
+ if !trait_pred.has_infer() {
debug!(?trait_pred, ?result, "insert_evaluation_cache global");
// This may overwrite the cache with the same value
// FIXME: Due to #50507 this overwrites the different values
@@ -1517,7 +1524,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
// If there are any inference variables in the `ParamEnv`, then we
// always use a cache local to this particular scope. Otherwise, we
// switch to a global cache.
- if param_env.needs_infer() {
+ if param_env.has_infer() {
return false;
}
@@ -1588,7 +1595,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
return false;
}
match result {
- Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.needs_infer(),
+ Ok(Some(SelectionCandidate::ParamCandidate(trait_ref))) => !trait_ref.has_infer(),
_ => true,
}
}
@@ -1614,8 +1621,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
if self.can_use_global_caches(param_env) {
if let Err(Overflow(OverflowError::Canonical)) = candidate {
// Don't cache overflow globally; we only produce this in certain modes.
- } else if !pred.needs_infer() {
- if !candidate.needs_infer() {
+ } else if !pred.has_infer() {
+ if !candidate.has_infer() {
debug!(?pred, ?candidate, "insert_candidate_cache global");
// This may overwrite the cache with the same value.
tcx.selection_cache.insert((param_env, pred), dep_node, candidate);
@@ -1646,7 +1653,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
let tcx = self.infcx.tcx;
let (def_id, substs) = match *placeholder_trait_predicate.trait_ref.self_ty().kind() {
- ty::Alias(_, ty::AliasTy { def_id, substs, .. }) => (def_id, substs),
+ ty::Alias(ty::Projection | ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
+ (def_id, substs)
+ }
_ => {
span_bug!(
obligation.cause.span,
@@ -1725,7 +1734,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.map(|InferOk { obligations: _, value: () }| {
// This method is called within a probe, so we can't have
// inference variables and placeholders escape.
- if !trait_bound.needs_infer() && !trait_bound.has_placeholders() {
+ if !trait_bound.has_infer() && !trait_bound.has_placeholders() {
Some(trait_bound)
} else {
None
@@ -1784,12 +1793,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
.infcx
.at(&obligation.cause, obligation.param_env)
.sup(DefineOpaqueTypes::No, obligation.predicate, infer_projection)
- .map_or(false, |InferOk { obligations, value: () }| {
+ .is_ok_and(|InferOk { obligations, value: () }| {
self.evaluate_predicates_recursively(
TraitObligationStackList::empty(&ProvisionalEvaluationCache::default()),
nested_obligations.into_iter().chain(obligations),
)
- .map_or(false, |res| res.may_apply())
+ .is_ok_and(|res| res.may_apply())
});
if is_match {
@@ -1841,7 +1850,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
&mut self,
victim: &EvaluatedCandidate<'tcx>,
other: &EvaluatedCandidate<'tcx>,
- needs_infer: bool,
+ has_non_region_infer: bool,
) -> DropVictim {
if victim.candidate == other.candidate {
return DropVictim::Yes;
@@ -1957,7 +1966,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| (ObjectCandidate(i), ObjectCandidate(j)) => {
// Arbitrarily pick the lower numbered candidate for backwards
// compatibility reasons. Don't let this affect inference.
- DropVictim::drop_if(i < j && !needs_infer)
+ DropVictim::drop_if(i < j && !has_non_region_infer)
}
(ObjectCandidate(_), ProjectionCandidate(..))
| (ProjectionCandidate(..), ObjectCandidate(_)) => {
@@ -2063,7 +2072,8 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// existence of multiple marker trait impls tells us nothing
// about which one should actually apply.
DropVictim::drop_if(
- !needs_infer && other.evaluation.must_apply_considering_regions(),
+ !has_non_region_infer
+ && other.evaluation.must_apply_considering_regions(),
)
}
None => DropVictim::No,
@@ -2315,7 +2325,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
| ty::Dynamic(..)
| ty::Param(..)
| ty::Foreign(..)
- | ty::Alias(ty::Projection, ..)
+ | ty::Alias(ty::Projection | ty::Inherent, ..)
| ty::Bound(..)
| ty::Infer(ty::TyVar(_) | ty::FreshTy(_) | ty::FreshIntTy(_) | ty::FreshFloatTy(_)) => {
bug!("asked to assemble constituent types of unexpected type: {:?}", t);
@@ -2413,7 +2423,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
self.tcx(),
cause.clone(),
param_env,
- self.tcx().mk_trait_ref(trait_def_id, [normalized_ty]),
+ ty::TraitRef::new(self.tcx(), trait_def_id, [normalized_ty]),
);
obligations.push(obligation);
obligations
@@ -2449,7 +2459,7 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
// for a variable being generalized...
let guar = self.infcx.tcx.sess.delay_span_bug(
obligation.cause.span,
- &format!(
+ format!(
"Impl {:?} was matchable against {:?} but now is not",
impl_def_id, obligation
),
@@ -2647,14 +2657,19 @@ impl<'tcx> SelectionContext<'_, 'tcx> {
let predicates = predicates.instantiate_own(tcx, substs);
let mut obligations = Vec::with_capacity(predicates.len());
for (index, (predicate, span)) in predicates.into_iter().enumerate() {
- let cause = cause.clone().derived_cause(parent_trait_pred, |derived| {
- ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
- derived,
- impl_or_alias_def_id: def_id,
- impl_def_predicate_index: Some(index),
- span,
- }))
- });
+ let cause =
+ if Some(parent_trait_pred.def_id()) == tcx.lang_items().coerce_unsized_trait() {
+ cause.clone()
+ } else {
+ cause.clone().derived_cause(parent_trait_pred, |derived| {
+ ImplDerivedObligation(Box::new(ImplDerivedObligationCause {
+ derived,
+ impl_or_alias_def_id: def_id,
+ impl_def_predicate_index: Some(index),
+ span,
+ }))
+ })
+ };
let predicate = normalize_with_depth_to(
self,
param_env,
@@ -3007,16 +3022,16 @@ fn bind_generator_hidden_types_above<'tcx>(
// Only remap erased regions if we use them.
if considering_regions {
- ty = tcx.fold_regions(ty, |mut r, current_depth| {
- if let ty::ReErased = r.kind() {
+ ty = tcx.fold_regions(ty, |r, current_depth| match r.kind() {
+ ty::ReErased => {
let br = ty::BoundRegion {
var: ty::BoundVar::from_u32(counter),
kind: ty::BrAnon(None),
};
counter += 1;
- r = tcx.mk_re_late_bound(current_depth, br);
+ tcx.mk_re_late_bound(current_depth, br)
}
- r
+ r => bug!("unexpected region: {r:?}"),
})
}
diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
index 8546bbe52..9a4b72013 100644
--- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
+++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs
@@ -83,6 +83,30 @@ pub fn translate_substs<'tcx>(
source_substs: SubstsRef<'tcx>,
target_node: specialization_graph::Node,
) -> SubstsRef<'tcx> {
+ translate_substs_with_cause(
+ infcx,
+ param_env,
+ source_impl,
+ source_substs,
+ target_node,
+ |_, _| ObligationCause::dummy(),
+ )
+}
+
+/// Like [translate_substs], but obligations from the parent implementation
+/// are registered with the provided `ObligationCause`.
+///
+/// This is for reporting *region* errors from those bounds. Type errors should
+/// not happen because the specialization graph already checks for those, and
+/// will result in an ICE.
+pub fn translate_substs_with_cause<'tcx>(
+ infcx: &InferCtxt<'tcx>,
+ param_env: ty::ParamEnv<'tcx>,
+ source_impl: DefId,
+ source_substs: SubstsRef<'tcx>,
+ target_node: specialization_graph::Node,
+ cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
+) -> SubstsRef<'tcx> {
debug!(
"translate_substs({:?}, {:?}, {:?}, {:?})",
param_env, source_impl, source_substs, target_node
@@ -99,14 +123,13 @@ pub fn translate_substs<'tcx>(
return source_substs;
}
- fulfill_implication(infcx, param_env, source_trait_ref, target_impl).unwrap_or_else(
- |()| {
+ fulfill_implication(infcx, param_env, source_trait_ref, source_impl, target_impl, cause)
+ .unwrap_or_else(|()| {
bug!(
"When translating substitutions from {source_impl:?} to {target_impl:?}, \
the expected specialization failed to hold"
)
- },
- )
+ })
}
specialization_graph::Node::Trait(..) => source_trait_ref.substs,
};
@@ -153,20 +176,12 @@ pub(super) fn specializes(tcx: TyCtxt<'_>, (impl1_def_id, impl2_def_id): (DefId,
// Create an infcx, taking the predicates of impl1 as assumptions:
let infcx = tcx.infer_ctxt().build();
- let impl1_trait_ref =
- match traits::fully_normalize(&infcx, ObligationCause::dummy(), penv, impl1_trait_ref) {
- Ok(impl1_trait_ref) => impl1_trait_ref,
- Err(_errors) => {
- tcx.sess.delay_span_bug(
- tcx.def_span(impl1_def_id),
- format!("failed to fully normalize {impl1_trait_ref}"),
- );
- impl1_trait_ref
- }
- };
// Attempt to prove that impl2 applies, given all of the above.
- fulfill_implication(&infcx, penv, impl1_trait_ref, impl2_def_id).is_ok()
+ fulfill_implication(&infcx, penv, impl1_trait_ref, impl1_def_id, impl2_def_id, |_, _| {
+ ObligationCause::dummy()
+ })
+ .is_ok()
}
/// Attempt to fulfill all obligations of `target_impl` after unification with
@@ -178,23 +193,41 @@ fn fulfill_implication<'tcx>(
infcx: &InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
source_trait_ref: ty::TraitRef<'tcx>,
+ source_impl: DefId,
target_impl: DefId,
+ error_cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
) -> Result<SubstsRef<'tcx>, ()> {
debug!(
"fulfill_implication({:?}, trait_ref={:?} |- {:?} applies)",
param_env, source_trait_ref, target_impl
);
+ let source_trait_ref = match traits::fully_normalize(
+ &infcx,
+ ObligationCause::dummy(),
+ param_env,
+ source_trait_ref,
+ ) {
+ Ok(source_trait_ref) => source_trait_ref,
+ Err(_errors) => {
+ infcx.tcx.sess.delay_span_bug(
+ infcx.tcx.def_span(source_impl),
+ format!("failed to fully normalize {source_trait_ref}"),
+ );
+ source_trait_ref
+ }
+ };
+
let source_trait = ImplSubject::Trait(source_trait_ref);
let selcx = &mut SelectionContext::new(&infcx);
let target_substs = infcx.fresh_substs_for_item(DUMMY_SP, target_impl);
let (target_trait, obligations) =
- util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs);
+ util::impl_subject_and_oblig(selcx, param_env, target_impl, target_substs, error_cause);
// do the impls unify? If not, no specialization.
let Ok(InferOk { obligations: more_obligations, .. }) =
- infcx.at(&ObligationCause::dummy(), param_env, ).eq(DefineOpaqueTypes::No,source_trait, target_trait)
+ infcx.at(&ObligationCause::dummy(), param_env).eq(DefineOpaqueTypes::No, source_trait, target_trait)
else {
debug!(
"fulfill_implication: {:?} does not unify with {:?}",
@@ -373,7 +406,7 @@ fn report_conflicting_impls<'tcx>(
}
None => format!("conflicting implementation in crate `{}`", cname),
};
- err.note(&msg);
+ err.note(msg);
}
}
diff --git a/compiler/rustc_trait_selection/src/traits/structural_normalize.rs b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
new file mode 100644
index 000000000..af8dd0da5
--- /dev/null
+++ b/compiler/rustc_trait_selection/src/traits/structural_normalize.rs
@@ -0,0 +1,55 @@
+use rustc_infer::infer::at::At;
+use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind};
+use rustc_infer::traits::{FulfillmentError, TraitEngine};
+use rustc_middle::ty::{self, Ty};
+
+use crate::traits::{query::evaluate_obligation::InferCtxtExt, NormalizeExt, Obligation};
+
+pub trait StructurallyNormalizeExt<'tcx> {
+ fn structurally_normalize(
+ &self,
+ ty: Ty<'tcx>,
+ fulfill_cx: &mut dyn TraitEngine<'tcx>,
+ ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>>;
+}
+
+impl<'tcx> StructurallyNormalizeExt<'tcx> for At<'_, 'tcx> {
+ fn structurally_normalize(
+ &self,
+ mut ty: Ty<'tcx>,
+ fulfill_cx: &mut dyn TraitEngine<'tcx>,
+ ) -> Result<Ty<'tcx>, Vec<FulfillmentError<'tcx>>> {
+ assert!(!ty.is_ty_var(), "should have resolved vars before calling");
+
+ if self.infcx.tcx.trait_solver_next() {
+ while let ty::Alias(ty::Projection, projection_ty) = *ty.kind() {
+ let new_infer_ty = self.infcx.next_ty_var(TypeVariableOrigin {
+ kind: TypeVariableOriginKind::NormalizeProjectionType,
+ span: self.cause.span,
+ });
+ let obligation = Obligation::new(
+ self.infcx.tcx,
+ self.cause.clone(),
+ self.param_env,
+ ty::Binder::dummy(ty::ProjectionPredicate {
+ projection_ty,
+ term: new_infer_ty.into(),
+ }),
+ );
+ if self.infcx.predicate_may_hold(&obligation) {
+ fulfill_cx.register_predicate_obligation(self.infcx, obligation);
+ let errors = fulfill_cx.select_where_possible(self.infcx);
+ if !errors.is_empty() {
+ return Err(errors);
+ }
+ ty = self.infcx.resolve_vars_if_possible(new_infer_ty);
+ } else {
+ break;
+ }
+ }
+ Ok(ty)
+ } else {
+ Ok(self.normalize(ty).into_value_registering_obligations(self.infcx, fulfill_cx))
+ }
+ }
+}
diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs
index 20357d4d2..82f3df401 100644
--- a/compiler/rustc_trait_selection/src/traits/util.rs
+++ b/compiler/rustc_trait_selection/src/traits/util.rs
@@ -197,6 +197,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
param_env: ty::ParamEnv<'tcx>,
impl_def_id: DefId,
impl_substs: SubstsRef<'tcx>,
+ cause: impl Fn(usize, Span) -> ObligationCause<'tcx>,
) -> (ImplSubject<'tcx>, impl Iterator<Item = PredicateObligation<'tcx>>) {
let subject = selcx.tcx().impl_subject(impl_def_id);
let subject = subject.subst(selcx.tcx(), impl_substs);
@@ -208,8 +209,7 @@ pub fn impl_subject_and_oblig<'a, 'tcx>(
let predicates = predicates.instantiate(selcx.tcx(), impl_substs);
let InferOk { value: predicates, obligations: normalization_obligations2 } =
selcx.infcx.at(&ObligationCause::dummy(), param_env).normalize(predicates);
- let impl_obligations =
- super::predicates_for_generics(|_, _| ObligationCause::dummy(), param_env, predicates);
+ let impl_obligations = super::predicates_for_generics(cause, param_env, predicates);
let impl_obligations = impl_obligations
.chain(normalization_obligations1.into_iter())
@@ -243,16 +243,11 @@ pub fn get_vtable_index_of_object_method<'tcx, N>(
) -> Option<usize> {
// Count number of methods preceding the one we are selecting and
// add them to the total offset.
- if let Some(index) = tcx
- .own_existential_vtable_entries(object.upcast_trait_ref.def_id())
+ tcx.own_existential_vtable_entries(object.upcast_trait_ref.def_id())
.iter()
.copied()
.position(|def_id| def_id == method_def_id)
- {
- Some(object.vtable_base + index)
- } else {
- None
- }
+ .map(|index| object.vtable_base + index)
}
pub fn closure_trait_ref_and_return_type<'tcx>(
@@ -267,7 +262,7 @@ pub fn closure_trait_ref_and_return_type<'tcx>(
TupleArgumentsFlag::No => sig.skip_binder().inputs()[0],
TupleArgumentsFlag::Yes => tcx.mk_tup(sig.skip_binder().inputs()),
};
- let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, arguments_tuple]);
+ let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, arguments_tuple]);
sig.map_bound(|sig| (trait_ref, sig.output()))
}
@@ -278,7 +273,7 @@ pub fn generator_trait_ref_and_outputs<'tcx>(
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>, Ty<'tcx>)> {
assert!(!self_ty.has_escaping_bound_vars());
- let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]);
+ let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty, sig.skip_binder().resume_ty]);
sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty))
}
@@ -289,7 +284,7 @@ pub fn future_trait_ref_and_outputs<'tcx>(
sig: ty::PolyGenSig<'tcx>,
) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> {
assert!(!self_ty.has_escaping_bound_vars());
- let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty]);
+ let trait_ref = ty::TraitRef::new(tcx, fn_trait_def_id, [self_ty]);
sig.map_bound(|sig| (trait_ref, sig.return_ty))
}
diff --git a/compiler/rustc_trait_selection/src/traits/vtable.rs b/compiler/rustc_trait_selection/src/traits/vtable.rs
index a4e9928f8..cc674ceee 100644
--- a/compiler/rustc_trait_selection/src/traits/vtable.rs
+++ b/compiler/rustc_trait_selection/src/traits/vtable.rs
@@ -4,6 +4,7 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_infer::traits::util::PredicateSet;
use rustc_infer::traits::ImplSource;
+use rustc_middle::query::Providers;
use rustc_middle::ty::visit::TypeVisitableExt;
use rustc_middle::ty::InternalSubsts;
use rustc_middle::ty::{self, GenericParamDefKind, ToPredicate, Ty, TyCtxt, VtblEntry};
@@ -353,13 +354,13 @@ pub(crate) fn vtable_trait_upcasting_coercion_new_vptr_slot<'tcx>(
),
) -> Option<usize> {
let (source, target) = key;
- assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.needs_infer());
- assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.needs_infer());
+ assert!(matches!(&source.kind(), &ty::Dynamic(..)) && !source.has_infer());
+ assert!(matches!(&target.kind(), &ty::Dynamic(..)) && !target.has_infer());
// this has been typecked-before, so diagnostics is not really needed.
let unsize_trait_did = tcx.require_lang_item(LangItem::Unsize, None);
- let trait_ref = tcx.mk_trait_ref(unsize_trait_did, [source, target]);
+ let trait_ref = ty::TraitRef::new(tcx, unsize_trait_did, [source, target]);
match tcx.codegen_select_candidate((ty::ParamEnv::reveal_all(), ty::Binder::dummy(trait_ref))) {
Ok(ImplSource::TraitUpcasting(implsrc_traitcasting)) => {
@@ -379,8 +380,8 @@ pub(crate) fn count_own_vtable_entries<'tcx>(
tcx.own_existential_vtable_entries(trait_ref.def_id()).len()
}
-pub(super) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub(super) fn provide(providers: &mut Providers) {
+ *providers = Providers {
own_existential_vtable_entries,
vtable_entries,
vtable_trait_upcasting_coercion_new_vptr_slot,
diff --git a/compiler/rustc_trait_selection/src/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs
index 3d026506a..086ab32b5 100644
--- a/compiler/rustc_trait_selection/src/traits/wf.rs
+++ b/compiler/rustc_trait_selection/src/traits/wf.rs
@@ -58,15 +58,8 @@ pub fn obligations<'tcx>(
GenericArgKind::Lifetime(..) => return Some(Vec::new()),
};
- let mut wf = WfPredicates {
- tcx: infcx.tcx,
- param_env,
- body_id,
- span,
- out: vec![],
- recursion_depth,
- item: None,
- };
+ let mut wf =
+ WfPredicates { infcx, param_env, body_id, span, out: vec![], recursion_depth, item: None };
wf.compute(arg);
debug!("wf::obligations({:?}, body_id={:?}) = {:?}", arg, body_id, wf.out);
@@ -91,7 +84,7 @@ pub fn unnormalized_obligations<'tcx>(
debug_assert_eq!(arg, infcx.resolve_vars_if_possible(arg));
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id: CRATE_DEF_ID,
span: DUMMY_SP,
@@ -116,7 +109,7 @@ pub fn trait_obligations<'tcx>(
item: &'tcx hir::Item<'tcx>,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id,
span,
@@ -138,7 +131,7 @@ pub fn predicate_obligations<'tcx>(
span: Span,
) -> Vec<traits::PredicateObligation<'tcx>> {
let mut wf = WfPredicates {
- tcx: infcx.tcx,
+ infcx,
param_env,
body_id,
span,
@@ -170,37 +163,28 @@ pub fn predicate_obligations<'tcx>(
ty::PredicateKind::WellFormed(arg) => {
wf.compute(arg);
}
- ty::PredicateKind::ObjectSafe(_) => {}
- ty::PredicateKind::ClosureKind(..) => {}
- ty::PredicateKind::Subtype(ty::SubtypePredicate { a, b, a_is_expected: _ }) => {
- wf.compute(a.into());
- wf.compute(b.into());
- }
- ty::PredicateKind::Coerce(ty::CoercePredicate { a, b }) => {
- wf.compute(a.into());
- wf.compute(b.into());
- }
+
ty::PredicateKind::ConstEvaluatable(ct) => {
wf.compute(ct.into());
}
- ty::PredicateKind::ConstEquate(c1, c2) => {
- wf.compute(c1.into());
- wf.compute(c2.into());
- }
- ty::PredicateKind::Ambiguous => {}
- ty::PredicateKind::TypeWellFormedFromEnv(..) => {
- bug!("TypeWellFormedFromEnv is only used for Chalk")
- }
- ty::PredicateKind::AliasRelate(..) => {
- bug!("We should only wf check where clauses and `AliasRelate` is not a `Clause`")
+
+ ty::PredicateKind::ObjectSafe(_)
+ | ty::PredicateKind::ClosureKind(..)
+ | ty::PredicateKind::Subtype(..)
+ | ty::PredicateKind::Coerce(..)
+ | ty::PredicateKind::ConstEquate(..)
+ | ty::PredicateKind::Ambiguous
+ | ty::PredicateKind::AliasRelate(..)
+ | ty::PredicateKind::TypeWellFormedFromEnv(..) => {
+ bug!("We should only wf check where clauses, unexpected predicate: {predicate:?}")
}
}
wf.normalize(infcx)
}
-struct WfPredicates<'tcx> {
- tcx: TyCtxt<'tcx>,
+struct WfPredicates<'a, 'tcx> {
+ infcx: &'a InferCtxt<'tcx>,
param_env: ty::ParamEnv<'tcx>,
body_id: LocalDefId,
span: Span,
@@ -299,9 +283,9 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>(
}
}
-impl<'tcx> WfPredicates<'tcx> {
+impl<'a, 'tcx> WfPredicates<'a, 'tcx> {
fn tcx(&self) -> TyCtxt<'tcx> {
- self.tcx
+ self.infcx.tcx
}
fn cause(&self, code: traits::ObligationCauseCode<'tcx>) -> traits::ObligationCause<'tcx> {
@@ -334,9 +318,16 @@ impl<'tcx> WfPredicates<'tcx> {
/// Pushes the obligations required for `trait_ref` to be WF into `self.out`.
fn compute_trait_pred(&mut self, trait_pred: &ty::TraitPredicate<'tcx>, elaborate: Elaborate) {
- let tcx = self.tcx;
+ let tcx = self.tcx();
let trait_ref = &trait_pred.trait_ref;
+ // Negative trait predicates don't require supertraits to hold, just
+ // that their substs are WF.
+ if trait_pred.polarity == ty::ImplPolarity::Negative {
+ self.compute_negative_trait_pred(trait_ref);
+ return;
+ }
+
// if the trait predicate is not const, the wf obligations should not be const as well.
let obligations = if trait_pred.constness == ty::BoundConstness::NotConst {
self.nominal_obligations_without_const(trait_ref.def_id, trait_ref.substs)
@@ -371,7 +362,6 @@ impl<'tcx> WfPredicates<'tcx> {
self.out.extend(obligations);
}
- let tcx = self.tcx();
self.out.extend(
trait_ref
.substs
@@ -402,6 +392,14 @@ impl<'tcx> WfPredicates<'tcx> {
);
}
+ // Compute the obligations that are required for `trait_ref` to be WF,
+ // given that it is a *negative* trait predicate.
+ fn compute_negative_trait_pred(&mut self, trait_ref: &ty::TraitRef<'tcx>) {
+ for arg in trait_ref.substs {
+ self.compute(arg);
+ }
+ }
+
/// Pushes the obligations required for `trait_ref::Item` to be WF
/// into `self.out`.
fn compute_projection(&mut self, data: ty::AliasTy<'tcx>) {
@@ -430,13 +428,45 @@ impl<'tcx> WfPredicates<'tcx> {
let obligations = self.nominal_obligations_without_const(data.def_id, data.substs);
self.out.extend(obligations);
+ self.compute_projection_substs(data.substs);
+ }
+
+ fn compute_inherent_projection(&mut self, data: ty::AliasTy<'tcx>) {
+ // An inherent projection is well-formed if
+ //
+ // (a) its predicates hold (*)
+ // (b) its substs are wf
+ //
+ // (*) The predicates of an inherent associated type include the
+ // predicates of the impl that it's contained in.
+
+ if !data.self_ty().has_escaping_bound_vars() {
+ // FIXME(inherent_associated_types): Should this happen inside of a snapshot?
+ // FIXME(inherent_associated_types): This is incompatible with the new solver and lazy norm!
+ let substs = traits::project::compute_inherent_assoc_ty_substs(
+ &mut traits::SelectionContext::new(self.infcx),
+ self.param_env,
+ data,
+ self.cause(traits::WellFormed(None)),
+ self.recursion_depth,
+ &mut self.out,
+ );
+ // Inherent projection types do not require const predicates.
+ let obligations = self.nominal_obligations_without_const(data.def_id, substs);
+ self.out.extend(obligations);
+ }
+
+ self.compute_projection_substs(data.substs);
+ }
+
+ fn compute_projection_substs(&mut self, substs: SubstsRef<'tcx>) {
let tcx = self.tcx();
let cause = self.cause(traits::WellFormed(None));
let param_env = self.param_env;
let depth = self.recursion_depth;
self.out.extend(
- data.substs
+ substs
.iter()
.filter(|arg| {
matches!(arg.unpack(), GenericArgKind::Type(..) | GenericArgKind::Const(..))
@@ -457,9 +487,10 @@ impl<'tcx> WfPredicates<'tcx> {
fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>) {
if !subty.has_escaping_bound_vars() {
let cause = self.cause(cause);
- let trait_ref = self.tcx.at(cause.span).mk_trait_ref(LangItem::Sized, [subty]);
+ let trait_ref =
+ ty::TraitRef::from_lang_item(self.tcx(), LangItem::Sized, cause.span, [subty]);
self.out.push(traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,
@@ -487,7 +518,7 @@ impl<'tcx> WfPredicates<'tcx> {
match ct.kind() {
ty::ConstKind::Unevaluated(uv) => {
if !ct.has_escaping_bound_vars() {
- let obligations = self.nominal_obligations(uv.def.did, uv.substs);
+ let obligations = self.nominal_obligations(uv.def, uv.substs);
self.out.extend(obligations);
let predicate =
@@ -598,6 +629,10 @@ impl<'tcx> WfPredicates<'tcx> {
walker.skip_current_subtree(); // Subtree handled by compute_projection.
self.compute_projection(data);
}
+ ty::Alias(ty::Inherent, data) => {
+ walker.skip_current_subtree(); // Subtree handled by compute_inherent_projection.
+ self.compute_inherent_projection(data);
+ }
ty::Adt(def, substs) => {
// WfNominalType
@@ -690,7 +725,7 @@ impl<'tcx> WfPredicates<'tcx> {
// All of the requirements on type parameters
// have already been checked for `impl Trait` in
// return position. We do need to check type-alias-impl-trait though.
- if self.tcx.is_type_alias_impl_trait(def_id) {
+ if self.tcx().is_type_alias_impl_trait(def_id) {
let obligations = self.nominal_obligations(def_id, substs);
self.out.extend(obligations);
}
@@ -760,15 +795,15 @@ impl<'tcx> WfPredicates<'tcx> {
substs: SubstsRef<'tcx>,
remap_constness: bool,
) -> Vec<traits::PredicateObligation<'tcx>> {
- let predicates = self.tcx.predicates_of(def_id);
+ let predicates = self.tcx().predicates_of(def_id);
let mut origins = vec![def_id; predicates.predicates.len()];
let mut head = predicates;
while let Some(parent) = head.parent {
- head = self.tcx.predicates_of(parent);
+ head = self.tcx().predicates_of(parent);
origins.extend(iter::repeat(parent).take(head.predicates.len()));
}
- let predicates = predicates.instantiate(self.tcx, substs);
+ let predicates = predicates.instantiate(self.tcx(), substs);
trace!("{:#?}", predicates);
debug_assert_eq!(predicates.predicates.len(), origins.len());
@@ -781,10 +816,10 @@ impl<'tcx> WfPredicates<'tcx> {
};
let cause = self.cause(code);
if remap_constness {
- pred = pred.without_const(self.tcx);
+ pred = pred.without_const(self.tcx());
}
traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,
@@ -849,7 +884,7 @@ impl<'tcx> WfPredicates<'tcx> {
// Note: in fact we only permit builtin traits, not `Bar<'d>`, I
// am looking forward to the future here.
if !data.has_escaping_bound_vars() && !region.has_escaping_bound_vars() {
- let implicit_bounds = object_region_bounds(self.tcx, data);
+ let implicit_bounds = object_region_bounds(self.tcx(), data);
let explicit_bound = region;
@@ -859,7 +894,7 @@ impl<'tcx> WfPredicates<'tcx> {
let outlives =
ty::Binder::dummy(ty::OutlivesPredicate(explicit_bound, implicit_bound));
self.out.push(traits::Obligation::with_depth(
- self.tcx,
+ self.tcx(),
cause,
self.recursion_depth,
self.param_env,
diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml
index eff6fb26d..dfd6fbff7 100644
--- a/compiler/rustc_traits/Cargo.toml
+++ b/compiler/rustc_traits/Cargo.toml
@@ -8,7 +8,6 @@ tracing = "0.1"
rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_hir = { path = "../rustc_hir" }
-rustc_index = { path = "../rustc_index" }
rustc_ast = { path = "../rustc_ast" }
rustc_span = { path = "../rustc_span" }
rustc_target = { path = "../rustc_target" }
diff --git a/compiler/rustc_traits/src/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs
index 9683e4847..c319b2e31 100644
--- a/compiler/rustc_traits/src/chalk/db.rs
+++ b/compiler/rustc_traits/src/chalk/db.rs
@@ -50,12 +50,11 @@ impl<'tcx> RustIrDatabase<'tcx> {
where
ty::Predicate<'tcx>: LowerInto<'tcx, std::option::Option<T>>,
{
- let bounds = self.interner.tcx.bound_explicit_item_bounds(def_id);
- bounds
- .0
- .iter()
- .map(|(bound, _)| bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars))
- .filter_map(|bound| LowerInto::<Option<_>>::lower_into(bound, self.interner))
+ self.interner
+ .tcx
+ .explicit_item_bounds(def_id)
+ .subst_iter_copied(self.interner.tcx, &bound_vars)
+ .filter_map(|(bound, _)| LowerInto::<Option<_>>::lower_into(bound, self.interner))
.collect()
}
}
@@ -506,15 +505,11 @@ impl<'tcx> chalk_solve::RustIrDatabase<RustInterner<'tcx>> for RustIrDatabase<'t
let identity_substs = InternalSubsts::identity_for_item(self.interner.tcx, opaque_ty_id.0);
- let explicit_item_bounds = self.interner.tcx.bound_explicit_item_bounds(opaque_ty_id.0);
+ let explicit_item_bounds = self.interner.tcx.explicit_item_bounds(opaque_ty_id.0);
let bounds =
explicit_item_bounds
- .0
- .iter()
+ .subst_iter_copied(self.interner.tcx, &bound_vars)
.map(|(bound, _)| {
- explicit_item_bounds.rebind(*bound).subst(self.interner.tcx, &bound_vars)
- })
- .map(|bound| {
bound.fold_with(&mut ReplaceOpaqueTyFolder {
tcx: self.interner.tcx,
opaque_ty_id,
diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs
index 2be72879b..e447ab94f 100644
--- a/compiler/rustc_traits/src/chalk/lowering.rs
+++ b/compiler/rustc_traits/src/chalk/lowering.rs
@@ -60,6 +60,20 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>> for Subst
}
}
+impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution<RustInterner<'tcx>>>
+ for &'tcx ty::List<Ty<'tcx>>
+{
+ fn lower_into(
+ self,
+ interner: RustInterner<'tcx>,
+ ) -> chalk_ir::Substitution<RustInterner<'tcx>> {
+ chalk_ir::Substitution::from_iter(
+ interner,
+ self.iter().map(|ty| GenericArg::from(ty).lower_into(interner)),
+ )
+ }
+}
+
impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution<RustInterner<'tcx>> {
fn lower_into(self, interner: RustInterner<'tcx>) -> SubstsRef<'tcx> {
interner
@@ -351,15 +365,14 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty<RustInterner<'tcx>>> for Ty<'tcx> {
ty::GeneratorWitness(_) => unimplemented!(),
ty::GeneratorWitnessMIR(..) => unimplemented!(),
ty::Never => chalk_ir::TyKind::Never,
- ty::Tuple(types) => {
- chalk_ir::TyKind::Tuple(types.len(), types.as_substs().lower_into(interner))
- }
+ ty::Tuple(types) => chalk_ir::TyKind::Tuple(types.len(), types.lower_into(interner)),
ty::Alias(ty::Projection, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy {
associated_ty_id: chalk_ir::AssocTypeId(def_id),
substitution: substs.lower_into(interner),
}))
}
+ ty::Alias(ty::Inherent, _) => unimplemented!(),
ty::Alias(ty::Opaque, ty::AliasTy { def_id, substs, .. }) => {
chalk_ir::TyKind::Alias(chalk_ir::AliasTy::Opaque(chalk_ir::OpaqueTy {
opaque_ty_id: chalk_ir::OpaqueTyId(def_id),
@@ -435,7 +448,7 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
TyKind::GeneratorWitness(..) => unimplemented!(),
TyKind::Never => ty::Never,
TyKind::Tuple(_len, substitution) => {
- ty::Tuple(substitution.lower_into(interner).try_as_type_list().unwrap())
+ ty::Tuple(substitution.lower_into(interner).into_type_list(interner.tcx))
}
TyKind::Slice(ty) => ty::Slice(ty.lower_into(interner)),
TyKind::Raw(mutbl, ty) => ty::RawPtr(ty::TypeAndMut {
@@ -666,7 +679,7 @@ impl<'tcx> LowerInto<'tcx, Option<chalk_ir::QuantifiedWhereClause<RustInterner<'
| ty::PredicateKind::ConstEquate(..)
| ty::PredicateKind::Ambiguous
| ty::PredicateKind::TypeWellFormedFromEnv(..) => {
- bug!("unexpected predicate {}", &self)
+ bug!("unexpected predicate {self}")
}
};
value.map(|value| chalk_ir::Binders::new(binders, value))
@@ -998,7 +1011,7 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for BoundVarsCollector<'tcx> {
_ => (),
};
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
}
@@ -1048,7 +1061,7 @@ impl<'a, 'tcx> TypeFolder<TyCtxt<'tcx>> for NamedBoundVarSubstitutor<'a, 'tcx> {
_ => (),
};
- r.super_fold_with(self)
+ r
}
}
@@ -1142,7 +1155,7 @@ impl<'tcx> TypeFolder<TyCtxt<'tcx>> for ParamsSubstitutor<'tcx> {
}
},
- _ => r.super_fold_with(self),
+ _ => r,
}
}
}
@@ -1223,6 +1236,6 @@ impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for PlaceholdersCollector {
_ => (),
};
- r.super_visit_with(self)
+ ControlFlow::Continue(())
}
}
diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs
index a5ebc26a8..8834449c9 100644
--- a/compiler/rustc_traits/src/chalk/mod.rs
+++ b/compiler/rustc_traits/src/chalk/mod.rs
@@ -7,8 +7,8 @@ pub(crate) mod db;
pub(crate) mod lowering;
use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind};
+use rustc_middle::query::Providers;
use rustc_middle::traits::ChalkRustInterner;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, TyCtxt, TypeFoldable, TypeVisitable};
use rustc_infer::infer::canonical::{
diff --git a/compiler/rustc_traits/src/codegen.rs b/compiler/rustc_traits/src/codegen.rs
index 6f81d343e..ddba03b0b 100644
--- a/compiler/rustc_traits/src/codegen.rs
+++ b/compiler/rustc_traits/src/codegen.rs
@@ -3,9 +3,9 @@
// seems likely that they should eventually be merged into more
// general routines.
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
+use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::{FulfillmentErrorCode, TraitEngineExt as _};
-use rustc_middle::traits::CodegenObligationError;
+use rustc_middle::traits::{CodegenObligationError, DefiningAnchor};
use rustc_middle::ty::{self, TyCtxt};
use rustc_trait_selection::traits::error_reporting::TypeErrCtxtExt;
use rustc_trait_selection::traits::{
diff --git a/compiler/rustc_traits/src/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs
index 58117c46f..f35c14eea 100644
--- a/compiler/rustc_traits/src/dropck_outlives.rs
+++ b/compiler/rustc_traits/src/dropck_outlives.rs
@@ -2,18 +2,15 @@ use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
+use rustc_middle::traits::query::{DropckConstraint, DropckOutlivesResult};
use rustc_middle::ty::InternalSubsts;
-use rustc_middle::ty::{self, EarlyBinder, ParamEnvAnd, Ty, TyCtxt};
-use rustc_span::source_map::{Span, DUMMY_SP};
+use rustc_middle::ty::TyCtxt;
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,
+ compute_dropck_outlives_inner, dtorck_constraint_for_ty_inner,
};
-use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
-use rustc_trait_selection::traits::{Normalized, ObligationCause};
pub(crate) fn provide(p: &mut Providers) {
*p = Providers { dropck_outlives, adt_dtorck_constraint, ..*p };
@@ -26,263 +23,10 @@ fn dropck_outlives<'tcx>(
debug!("dropck_outlives(goal={:#?})", canonical_goal);
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(..) {
- let Normalized { value: ty, obligations } =
- ocx.infcx.at(&cause, param_env).query_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::Alias(..) => {
- result.kinds.push(ty.into());
- }
-
- _ => {
- if ty_set.insert(ty) {
- ty_stack.push((ty, depth + 1));
- }
- }
- }
- }
- }
-
- debug!("dropck_outlives: result = {:#?}", result);
- Ok(result)
+ compute_dropck_outlives_inner(ocx, goal)
})
}
-/// Returns a set of constraints that needs to be satisfied in
-/// order for `ty` to be valid for destruction.
-fn dtorck_constraint_for_ty<'tcx>(
- tcx: TyCtxt<'tcx>,
- span: Span,
- for_ty: Ty<'tcx>,
- depth: usize,
- ty: Ty<'tcx>,
- constraints: &mut DropckConstraint<'tcx>,
-) -> Result<(), NoSolution> {
- debug!("dtorck_constraint_for_ty({:?}, {:?}, {:?}, {:?})", span, for_ty, depth, ty);
-
- if !tcx.recursion_limit().value_within_limit(depth) {
- constraints.overflows.push(ty);
- return Ok(());
- }
-
- if trivial_dropck_outlives(tcx, ty) {
- return Ok(());
- }
-
- match ty.kind() {
- ty::Bool
- | ty::Char
- | ty::Int(_)
- | ty::Uint(_)
- | ty::Float(_)
- | ty::Str
- | ty::Never
- | ty::Foreign(..)
- | ty::RawPtr(..)
- | ty::Ref(..)
- | ty::FnDef(..)
- | ty::FnPtr(_)
- | ty::GeneratorWitness(..)
- | ty::GeneratorWitnessMIR(..) => {
- // these types never have a destructor
- }
-
- ty::Array(ety, _) | ty::Slice(ety) => {
- // single-element containers, behave like their element
- rustc_data_structures::stack::ensure_sufficient_stack(|| {
- dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, *ety, constraints)
- })?;
- }
-
- ty::Tuple(tys) => rustc_data_structures::stack::ensure_sufficient_stack(|| {
- for ty in tys.iter() {
- dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
- }
- Ok::<_, NoSolution>(())
- })?,
-
- ty::Closure(_, substs) => {
- if !substs.as_closure().is_valid() {
- // By the time this code runs, all type variables ought to
- // be fully resolved.
-
- tcx.sess.delay_span_bug(
- span,
- &format!("upvar_tys for closure not found. Expected capture information for closure {ty}",),
- );
- return Err(NoSolution);
- }
-
- rustc_data_structures::stack::ensure_sufficient_stack(|| {
- for ty in substs.as_closure().upvar_tys() {
- dtorck_constraint_for_ty(tcx, span, for_ty, depth + 1, ty, constraints)?;
- }
- Ok::<_, NoSolution>(())
- })?
- }
-
- ty::Generator(_, substs, _movability) => {
- // rust-lang/rust#49918: types can be constructed, stored
- // in the interior, and sit idle when generator yields
- // (and is subsequently dropped).
- //
- // It would be nice to descend into interior of a
- // generator to determine what effects dropping it might
- // have (by looking at any drop effects associated with
- // its interior).
- //
- // However, the interior's representation uses things like
- // GeneratorWitness that explicitly assume they are not
- // traversed in such a manner. So instead, we will
- // simplify things for now by treating all generators as
- // if they were like trait objects, where its upvars must
- // all be alive for the generator's (potential)
- // destructor.
- //
- // In particular, skipping over `_interior` is safe
- // because any side-effects from dropping `_interior` can
- // only take place through references with lifetimes
- // derived from lifetimes attached to the upvars and resume
- // argument, and we *do* incorporate those here.
-
- if !substs.as_generator().is_valid() {
- // By the time this code runs, all type variables ought to
- // be fully resolved.
- tcx.sess.delay_span_bug(
- span,
- &format!("upvar_tys for generator not found. Expected capture information for generator {ty}",),
- );
- return Err(NoSolution);
- }
-
- constraints.outlives.extend(
- substs
- .as_generator()
- .upvar_tys()
- .map(|t| -> ty::subst::GenericArg<'tcx> { t.into() }),
- );
- constraints.outlives.push(substs.as_generator().resume_ty().into());
- }
-
- ty::Adt(def, substs) => {
- let DropckConstraint { dtorck_types, outlives, overflows } =
- tcx.at(span).adt_dtorck_constraint(def.did())?;
- // FIXME: we can try to recursively `dtorck_constraint_on_ty`
- // there, but that needs some way to handle cycles.
- constraints
- .dtorck_types
- .extend(dtorck_types.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
- constraints
- .outlives
- .extend(outlives.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
- constraints
- .overflows
- .extend(overflows.iter().map(|t| EarlyBinder(*t).subst(tcx, substs)));
- }
-
- // Objects must be alive in order for their destructor
- // to be called.
- ty::Dynamic(..) => {
- constraints.outlives.push(ty.into());
- }
-
- // Types that can't be resolved. Pass them forward.
- ty::Alias(..) | ty::Param(..) => {
- constraints.dtorck_types.push(ty);
- }
-
- ty::Placeholder(..) | ty::Bound(..) | ty::Infer(..) | ty::Error(_) => {
- // By the time this code runs, all type variables ought to
- // be fully resolved.
- return Err(NoSolution);
- }
- }
-
- Ok(())
-}
-
/// Calculates the dtorck constraint for a type.
pub(crate) fn adt_dtorck_constraint(
tcx: TyCtxt<'_>,
@@ -311,7 +55,7 @@ pub(crate) fn adt_dtorck_constraint(
let mut result = DropckConstraint::empty();
for field in def.all_fields() {
let fty = tcx.type_of(field.did).subst_identity();
- dtorck_constraint_for_ty(tcx, span, fty, 0, fty, &mut result)?;
+ dtorck_constraint_for_ty_inner(tcx, span, fty, 0, fty, &mut result)?;
}
result.outlives.extend(tcx.destructor_constraints(def));
dedup_dtorck_constraint(&mut result);
diff --git a/compiler/rustc_traits/src/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs
index e94c8efe6..f5b2753b7 100644
--- a/compiler/rustc_traits/src/evaluate_obligation.rs
+++ b/compiler/rustc_traits/src/evaluate_obligation.rs
@@ -1,5 +1,6 @@
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_middle::ty::query::Providers;
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::query::Providers;
+use rustc_middle::traits::DefiningAnchor;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_span::source_map::DUMMY_SP;
use rustc_trait_selection::traits::query::CanonicalPredicateGoal;
@@ -15,6 +16,7 @@ fn evaluate_obligation<'tcx>(
tcx: TyCtxt<'tcx>,
canonical_goal: CanonicalPredicateGoal<'tcx>,
) -> Result<EvaluationResult, OverflowError> {
+ assert!(!tcx.trait_solver_next());
debug!("evaluate_obligation(canonical_goal={:#?})", canonical_goal);
// HACK This bubble is required for this tests to pass:
// impl-trait/issue99642.rs
diff --git a/compiler/rustc_traits/src/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs
index f5bba14d2..959838ab3 100644
--- a/compiler/rustc_traits/src/implied_outlives_bounds.rs
+++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs
@@ -3,18 +3,13 @@
//! [`rustc_trait_selection::traits::query::type_op::implied_outlives_bounds`].
use rustc_infer::infer::canonical::{self, Canonical};
-use rustc_infer::infer::outlives::components::{push_outlives_components, Component};
use rustc_infer::infer::TyCtxtInferExt;
use rustc_infer::traits::query::OutlivesBound;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, Ty, TyCtxt, TypeVisitableExt};
-use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::source_map::DUMMY_SP;
+use rustc_middle::query::Providers;
+use rustc_middle::ty::TyCtxt;
use rustc_trait_selection::infer::InferCtxtBuilderExt;
-use rustc_trait_selection::traits::query::{CanonicalTyGoal, Fallible, NoSolution};
-use rustc_trait_selection::traits::wf;
-use rustc_trait_selection::traits::ObligationCtxt;
-use smallvec::{smallvec, SmallVec};
+use rustc_trait_selection::traits::query::type_op::implied_outlives_bounds::compute_implied_outlives_bounds_inner;
+use rustc_trait_selection::traits::query::{CanonicalTyGoal, NoSolution};
pub(crate) fn provide(p: &mut Providers) {
*p = Providers { implied_outlives_bounds, ..*p };
@@ -29,164 +24,6 @@ fn implied_outlives_bounds<'tcx>(
> {
tcx.infer_ctxt().enter_canonical_trait_query(&goal, |ocx, key| {
let (param_env, ty) = key.into_parts();
- compute_implied_outlives_bounds(ocx, param_env, ty)
+ compute_implied_outlives_bounds_inner(ocx, param_env, ty)
})
}
-
-fn compute_implied_outlives_bounds<'tcx>(
- ocx: &ObligationCtxt<'_, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- ty: Ty<'tcx>,
-) -> Fallible<Vec<OutlivesBound<'tcx>>> {
- let tcx = ocx.infcx.tcx;
-
- // Sometimes when we ask what it takes for T: WF, we get back that
- // U: WF is required; in that case, we push U onto this stack and
- // process it next. Because the resulting predicates aren't always
- // guaranteed to be a subset of the original type, so we need to store the
- // WF args we've computed in a set.
- let mut checked_wf_args = rustc_data_structures::fx::FxHashSet::default();
- let mut wf_args = vec![ty.into()];
-
- let mut outlives_bounds: Vec<ty::OutlivesPredicate<ty::GenericArg<'tcx>, ty::Region<'tcx>>> =
- vec![];
-
- while let Some(arg) = wf_args.pop() {
- if !checked_wf_args.insert(arg) {
- continue;
- }
-
- // Compute the obligations for `arg` to be well-formed. If `arg` is
- // an unresolved inference variable, just substituted an empty set
- // -- because the return type here is going to be things we *add*
- // to the environment, it's always ok for this set to be smaller
- // than the ultimate set. (Note: normally there won't be
- // unresolved inference variables here anyway, but there might be
- // during typeck under some circumstances.)
- //
- // FIXME(@lcnr): It's not really "always fine", having fewer implied
- // bounds can be backward incompatible, e.g. #101951 was caused by
- // us not dealing with inference vars in `TypeOutlives` predicates.
- let obligations = wf::obligations(ocx.infcx, param_env, CRATE_DEF_ID, 0, arg, DUMMY_SP)
- .unwrap_or_default();
-
- for obligation in obligations {
- debug!(?obligation);
- assert!(!obligation.has_escaping_bound_vars());
-
- // While these predicates should all be implied by other parts of
- // the program, they are still relevant as they may constrain
- // inference variables, which is necessary to add the correct
- // implied bounds in some cases, mostly when dealing with projections.
- //
- // Another important point here: we only register `Projection`
- // predicates, since otherwise we might register outlives
- // predicates containing inference variables, and we don't
- // learn anything new from those.
- if obligation.predicate.has_non_region_infer() {
- match obligation.predicate.kind().skip_binder() {
- ty::PredicateKind::Clause(ty::Clause::Projection(..))
- | ty::PredicateKind::AliasRelate(..) => {
- ocx.register_obligation(obligation.clone());
- }
- _ => {}
- }
- }
-
- let pred = match obligation.predicate.kind().no_bound_vars() {
- None => continue,
- Some(pred) => pred,
- };
- match pred {
- ty::PredicateKind::Clause(ty::Clause::Trait(..))
- // FIXME(const_generics): Make sure that `<'a, 'b, const N: &'a &'b u32>` is sound
- // if we ever support that
- | ty::PredicateKind::Clause(ty::Clause::ConstArgHasType(..))
- | ty::PredicateKind::Subtype(..)
- | ty::PredicateKind::Coerce(..)
- | ty::PredicateKind::Clause(ty::Clause::Projection(..))
- | ty::PredicateKind::ClosureKind(..)
- | ty::PredicateKind::ObjectSafe(..)
- | ty::PredicateKind::ConstEvaluatable(..)
- | ty::PredicateKind::ConstEquate(..)
- | ty::PredicateKind::Ambiguous
- | ty::PredicateKind::AliasRelate(..)
- | ty::PredicateKind::TypeWellFormedFromEnv(..) => {}
-
- // We need to search through *all* WellFormed predicates
- ty::PredicateKind::WellFormed(arg) => {
- wf_args.push(arg);
- }
-
- // We need to register region relationships
- ty::PredicateKind::Clause(ty::Clause::RegionOutlives(ty::OutlivesPredicate(
- r_a,
- r_b,
- ))) => outlives_bounds.push(ty::OutlivesPredicate(r_a.into(), r_b)),
-
- ty::PredicateKind::Clause(ty::Clause::TypeOutlives(ty::OutlivesPredicate(
- ty_a,
- r_b,
- ))) => outlives_bounds.push(ty::OutlivesPredicate(ty_a.into(), r_b)),
- }
- }
- }
-
- // This call to `select_all_or_error` is necessary to constrain inference variables, which we
- // use further down when computing the implied bounds.
- match ocx.select_all_or_error().as_slice() {
- [] => (),
- _ => return Err(NoSolution),
- }
-
- // We lazily compute the outlives components as
- // `select_all_or_error` constrains inference variables.
- let implied_bounds = outlives_bounds
- .into_iter()
- .flat_map(|ty::OutlivesPredicate(a, r_b)| match a.unpack() {
- ty::GenericArgKind::Lifetime(r_a) => vec![OutlivesBound::RegionSubRegion(r_b, r_a)],
- ty::GenericArgKind::Type(ty_a) => {
- let ty_a = ocx.infcx.resolve_vars_if_possible(ty_a);
- let mut components = smallvec![];
- push_outlives_components(tcx, ty_a, &mut components);
- implied_bounds_from_components(r_b, components)
- }
- ty::GenericArgKind::Const(_) => unreachable!(),
- })
- .collect();
-
- Ok(implied_bounds)
-}
-
-/// When we have an implied bound that `T: 'a`, we can further break
-/// this down to determine what relationships would have to hold for
-/// `T: 'a` to hold. We get to assume that the caller has validated
-/// those relationships.
-fn implied_bounds_from_components<'tcx>(
- sub_region: ty::Region<'tcx>,
- sup_components: SmallVec<[Component<'tcx>; 4]>,
-) -> Vec<OutlivesBound<'tcx>> {
- sup_components
- .into_iter()
- .filter_map(|component| {
- match component {
- Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)),
- Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)),
- Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)),
- Component::EscapingAlias(_) =>
- // If the projection has escaping regions, don't
- // try to infer any implied bounds even for its
- // free components. This is conservative, because
- // the caller will still have to prove that those
- // free components outlive `sub_region`. But the
- // idea is that the WAY that the caller proves
- // that may change in the future and we want to
- // give ourselves room to get smarter here.
- {
- None
- }
- Component::UnresolvedInferenceVariable(..) => None,
- }
- })
- .collect()
-}
diff --git a/compiler/rustc_traits/src/lib.rs b/compiler/rustc_traits/src/lib.rs
index 8bea5588a..907e2d39c 100644
--- a/compiler/rustc_traits/src/lib.rs
+++ b/compiler/rustc_traits/src/lib.rs
@@ -21,9 +21,10 @@ mod normalize_erasing_regions;
mod normalize_projection_ty;
mod type_op;
-pub use type_op::{type_op_ascribe_user_type_with_span, type_op_prove_predicate_with_cause};
+pub use rustc_trait_selection::traits::query::type_op::ascribe_user_type::type_op_ascribe_user_type_with_span;
+pub use type_op::type_op_prove_predicate_with_cause;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
pub fn provide(p: &mut Providers) {
dropck_outlives::provide(p);
diff --git a/compiler/rustc_traits/src/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs
index 126a494f3..94c33efae 100644
--- a/compiler/rustc_traits/src/normalize_erasing_regions.rs
+++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs
@@ -1,6 +1,6 @@
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::query::Providers;
use rustc_middle::traits::query::NoSolution;
-use rustc_middle::ty::query::Providers;
use rustc_middle::ty::{self, ParamEnvAnd, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
use rustc_trait_selection::traits::{Normalized, ObligationCause};
@@ -47,7 +47,7 @@ fn try_normalize_after_erasing_regions<'tcx, T: TypeFoldable<TyCtxt<'tcx>> + Par
// us a test case.
debug_assert_eq!(normalized_value, resolved_value);
let erased = infcx.tcx.erase_regions(resolved_value);
- debug_assert!(!erased.needs_infer(), "{erased:?}");
+ debug_assert!(!erased.has_infer(), "{erased:?}");
Ok(erased)
}
Err(NoSolution) => Err(NoSolution),
diff --git a/compiler/rustc_traits/src/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs
index e805eb428..b552ba41a 100644
--- a/compiler/rustc_traits/src/normalize_projection_ty.rs
+++ b/compiler/rustc_traits/src/normalize_projection_ty.rs
@@ -1,6 +1,6 @@
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
use rustc_infer::infer::TyCtxtInferExt;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{ParamEnvAnd, TyCtxt};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::{
@@ -10,7 +10,7 @@ use rustc_trait_selection::traits::{self, ObligationCause, SelectionContext};
use std::sync::atomic::Ordering;
pub(crate) fn provide(p: &mut Providers) {
- *p = Providers { normalize_projection_ty, ..*p };
+ *p = Providers { normalize_projection_ty, normalize_inherent_projection_ty, ..*p };
}
fn normalize_projection_ty<'tcx>(
@@ -42,3 +42,30 @@ fn normalize_projection_ty<'tcx>(
},
)
}
+
+fn normalize_inherent_projection_ty<'tcx>(
+ tcx: TyCtxt<'tcx>,
+ goal: CanonicalProjectionGoal<'tcx>,
+) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, NormalizationResult<'tcx>>>, NoSolution> {
+ debug!("normalize_provider(goal={:#?})", goal);
+
+ tcx.infer_ctxt().enter_canonical_trait_query(
+ &goal,
+ |ocx, ParamEnvAnd { param_env, value: goal }| {
+ let selcx = &mut SelectionContext::new(ocx.infcx);
+ let cause = ObligationCause::dummy();
+ let mut obligations = vec![];
+ let answer = traits::normalize_inherent_projection(
+ selcx,
+ param_env,
+ goal,
+ cause,
+ 0,
+ &mut obligations,
+ );
+ ocx.register_obligations(obligations);
+
+ Ok(NormalizationResult { normalized_ty: answer })
+ },
+ )
+}
diff --git a/compiler/rustc_traits/src/type_op.rs b/compiler/rustc_traits/src/type_op.rs
index e0fd487b3..9904acb1c 100644
--- a/compiler/rustc_traits/src/type_op.rs
+++ b/compiler/rustc_traits/src/type_op.rs
@@ -1,21 +1,19 @@
-use rustc_hir as hir;
use rustc_infer::infer::canonical::{Canonical, QueryResponse};
-use rustc_infer::infer::{DefiningAnchor, TyCtxtInferExt};
-use rustc_infer::traits::ObligationCauseCode;
-use rustc_middle::ty::query::Providers;
-use rustc_middle::ty::{self, FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
+use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::query::Providers;
+use rustc_middle::traits::query::NoSolution;
+use rustc_middle::traits::DefiningAnchor;
+use rustc_middle::ty::{FnSig, Lift, PolyFnSig, Ty, TyCtxt, TypeFoldable};
use rustc_middle::ty::{ParamEnvAnd, Predicate};
-use rustc_middle::ty::{UserSelfTy, UserSubsts, UserType};
-use rustc_span::def_id::CRATE_DEF_ID;
-use rustc_span::{Span, DUMMY_SP};
use rustc_trait_selection::infer::InferCtxtBuilderExt;
use rustc_trait_selection::traits::query::normalize::QueryNormalizeExt;
-use rustc_trait_selection::traits::query::type_op::ascribe_user_type::AscribeUserType;
+use rustc_trait_selection::traits::query::type_op::ascribe_user_type::{
+ type_op_ascribe_user_type_with_span, AscribeUserType,
+};
use rustc_trait_selection::traits::query::type_op::eq::Eq;
use rustc_trait_selection::traits::query::type_op::normalize::Normalize;
use rustc_trait_selection::traits::query::type_op::prove_predicate::ProvePredicate;
use rustc_trait_selection::traits::query::type_op::subtype::Subtype;
-use rustc_trait_selection::traits::query::{Fallible, NoSolution};
use rustc_trait_selection::traits::{Normalized, Obligation, ObligationCause, ObligationCtxt};
use std::fmt;
@@ -42,110 +40,6 @@ fn type_op_ascribe_user_type<'tcx>(
})
}
-/// The core of the `type_op_ascribe_user_type` query: for diagnostics purposes in NLL HRTB errors,
-/// this query can be re-run to better track the span of the obligation cause, and improve the error
-/// message. Do not call directly unless you're in that very specific context.
-pub fn type_op_ascribe_user_type_with_span<'tcx>(
- ocx: &ObligationCtxt<'_, 'tcx>,
- key: ParamEnvAnd<'tcx, AscribeUserType<'tcx>>,
- span: Option<Span>,
-) -> Result<(), NoSolution> {
- let (param_env, AscribeUserType { mir_ty, user_ty }) = key.into_parts();
- debug!("type_op_ascribe_user_type: mir_ty={:?} user_ty={:?}", mir_ty, user_ty);
- let span = span.unwrap_or(DUMMY_SP);
- match user_ty {
- UserType::Ty(user_ty) => relate_mir_and_user_ty(ocx, param_env, span, mir_ty, user_ty)?,
- UserType::TypeOf(def_id, user_substs) => {
- relate_mir_and_user_substs(ocx, param_env, span, mir_ty, def_id, user_substs)?
- }
- };
- Ok(())
-}
-
-#[instrument(level = "debug", skip(ocx, param_env, span))]
-fn relate_mir_and_user_ty<'tcx>(
- ocx: &ObligationCtxt<'_, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- span: Span,
- mir_ty: Ty<'tcx>,
- user_ty: Ty<'tcx>,
-) -> Result<(), NoSolution> {
- let cause = ObligationCause::dummy_with_span(span);
- let user_ty = ocx.normalize(&cause, param_env, user_ty);
- ocx.eq(&cause, param_env, mir_ty, user_ty)?;
-
- // FIXME(#104764): We should check well-formedness before normalization.
- let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(user_ty.into()));
- ocx.register_obligation(Obligation::new(ocx.infcx.tcx, cause, param_env, predicate));
- Ok(())
-}
-
-#[instrument(level = "debug", skip(ocx, param_env, span))]
-fn relate_mir_and_user_substs<'tcx>(
- ocx: &ObligationCtxt<'_, 'tcx>,
- param_env: ty::ParamEnv<'tcx>,
- span: Span,
- mir_ty: Ty<'tcx>,
- def_id: hir::def_id::DefId,
- user_substs: UserSubsts<'tcx>,
-) -> Result<(), NoSolution> {
- let UserSubsts { user_self_ty, substs } = user_substs;
- let tcx = ocx.infcx.tcx;
- let cause = ObligationCause::dummy_with_span(span);
-
- let ty = tcx.type_of(def_id).subst(tcx, substs);
- let ty = ocx.normalize(&cause, param_env, ty);
- debug!("relate_type_and_user_type: ty of def-id is {:?}", ty);
-
- ocx.eq(&cause, param_env, mir_ty, ty)?;
-
- // Prove the predicates coming along with `def_id`.
- //
- // Also, normalize the `instantiated_predicates`
- // because otherwise we wind up with duplicate "type
- // outlives" error messages.
- let instantiated_predicates = tcx.predicates_of(def_id).instantiate(tcx, substs);
-
- debug!(?instantiated_predicates);
- for (instantiated_predicate, predicate_span) in instantiated_predicates {
- let span = if span == DUMMY_SP { predicate_span } else { span };
- let cause = ObligationCause::new(
- span,
- CRATE_DEF_ID,
- ObligationCauseCode::AscribeUserTypeProvePredicate(predicate_span),
- );
- let instantiated_predicate =
- ocx.normalize(&cause.clone(), param_env, instantiated_predicate);
-
- ocx.register_obligation(Obligation::new(tcx, cause, param_env, instantiated_predicate));
- }
-
- if let Some(UserSelfTy { impl_def_id, self_ty }) = user_self_ty {
- let self_ty = ocx.normalize(&cause, param_env, self_ty);
- let impl_self_ty = tcx.type_of(impl_def_id).subst(tcx, substs);
- let impl_self_ty = ocx.normalize(&cause, param_env, impl_self_ty);
-
- ocx.eq(&cause, param_env, self_ty, impl_self_ty)?;
- let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(impl_self_ty.into()));
- ocx.register_obligation(Obligation::new(tcx, cause.clone(), param_env, predicate));
- }
-
- // In addition to proving the predicates, we have to
- // prove that `ty` is well-formed -- this is because
- // the WF of `ty` is predicated on the substs being
- // well-formed, and we haven't proven *that*. We don't
- // want to prove the WF of types from `substs` directly because they
- // haven't been normalized.
- //
- // FIXME(nmatsakis): Well, perhaps we should normalize
- // them? This would only be relevant if some input
- // type were ill-formed but did not appear in `ty`,
- // which...could happen with normalization...
- let predicate = ty::Binder::dummy(ty::PredicateKind::WellFormed(ty.into()));
- ocx.register_obligation(Obligation::new(tcx, cause, param_env, predicate));
- Ok(())
-}
-
fn type_op_eq<'tcx>(
tcx: TyCtxt<'tcx>,
canonicalized: Canonical<'tcx, ParamEnvAnd<'tcx, Eq<'tcx>>>,
@@ -159,7 +53,7 @@ fn type_op_eq<'tcx>(
fn type_op_normalize<'tcx, T>(
ocx: &ObligationCtxt<'_, 'tcx>,
key: ParamEnvAnd<'tcx, Normalize<T>>,
-) -> Fallible<T>
+) -> Result<T, NoSolution>
where
T: fmt::Debug + TypeFoldable<TyCtxt<'tcx>> + Lift<'tcx>,
{
diff --git a/compiler/rustc_transmute/src/layout/tree.rs b/compiler/rustc_transmute/src/layout/tree.rs
index 2a89494c8..a6d88b134 100644
--- a/compiler/rustc_transmute/src/layout/tree.rs
+++ b/compiler/rustc_transmute/src/layout/tree.rs
@@ -196,7 +196,7 @@ pub(crate) mod rustc {
fn from(err: LayoutError<'tcx>) -> Self {
match err {
LayoutError::Unknown(..) => Self::Unknown,
- err @ _ => unimplemented!("{:?}", err),
+ err => unimplemented!("{:?}", err),
}
}
}
diff --git a/compiler/rustc_transmute/src/lib.rs b/compiler/rustc_transmute/src/lib.rs
index a93a42987..77c0526e3 100644
--- a/compiler/rustc_transmute/src/lib.rs
+++ b/compiler/rustc_transmute/src/lib.rs
@@ -62,16 +62,15 @@ mod rustc {
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::InferCtxt;
- use rustc_macros::{TypeFoldable, TypeVisitable};
+ use rustc_macros::TypeVisitable;
use rustc_middle::traits::ObligationCause;
- use rustc_middle::ty::Binder;
use rustc_middle::ty::Const;
use rustc_middle::ty::ParamEnv;
use rustc_middle::ty::Ty;
use rustc_middle::ty::TyCtxt;
/// The source and destination types of a transmutation.
- #[derive(TypeFoldable, TypeVisitable, Debug, Clone, Copy)]
+ #[derive(TypeVisitable, Debug, Clone, Copy)]
pub struct Types<'tcx> {
/// The source type.
pub src: Ty<'tcx>,
@@ -92,15 +91,13 @@ mod rustc {
pub fn is_transmutable(
&mut self,
cause: ObligationCause<'tcx>,
- src_and_dst: Binder<'tcx, Types<'tcx>>,
+ types: Types<'tcx>,
scope: Ty<'tcx>,
assume: crate::Assume,
) -> crate::Answer<crate::layout::rustc::Ref<'tcx>> {
- let src = src_and_dst.map_bound(|types| types.src).skip_binder();
- let dst = src_and_dst.map_bound(|types| types.dst).skip_binder();
crate::maybe_transmutable::MaybeTransmutableQuery::new(
- src,
- dst,
+ types.src,
+ types.dst,
scope,
assume,
self.infcx.tcx,
diff --git a/compiler/rustc_ty_utils/Cargo.toml b/compiler/rustc_ty_utils/Cargo.toml
index 52fbd3ae0..51885c9b4 100644
--- a/compiler/rustc_ty_utils/Cargo.toml
+++ b/compiler/rustc_ty_utils/Cargo.toml
@@ -9,6 +9,7 @@ rustc_middle = { path = "../rustc_middle" }
rustc_data_structures = { path = "../rustc_data_structures" }
rustc_errors = { path = "../rustc_errors" }
rustc_hir = { path = "../rustc_hir" }
+rustc_fluent_macro = { path = "../rustc_fluent_macro" }
rustc_infer = { path = "../rustc_infer" }
rustc_macros = { path = "../rustc_macros" }
rustc_span = { path = "../rustc_span" }
diff --git a/compiler/rustc_ty_utils/messages.ftl b/compiler/rustc_ty_utils/messages.ftl
index 15a14112f..c416aa52a 100644
--- a/compiler/rustc_ty_utils/messages.ftl
+++ b/compiler/rustc_ty_utils/messages.ftl
@@ -1,57 +1,65 @@
-ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop
+ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants
-ty_utils_generic_constant_too_complex = overly complex generic constant
- .help = consider moving this anonymous constant into a `const` function
- .maybe_supported = this operation may be supported in the future
+ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
-ty_utils_borrow_not_supported = borrowing is not supported in generic constants
+ty_utils_array_not_supported = array construction is not supported in generic constants
-ty_utils_address_and_deref_not_supported = dereferencing or taking the address is not supported in generic constants
+ty_utils_assign_not_supported = assignment is not supported in generic constants
-ty_utils_array_not_supported = array construction is not supported in generic constants
+ty_utils_binary_not_supported = unsupported binary operation in generic constants
ty_utils_block_not_supported = blocks are not supported in generic constants
-ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants
-
-ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
+ty_utils_borrow_not_supported = borrowing is not supported in generic constants
-ty_utils_index_not_supported = indexing is not supported in generic constants
+ty_utils_box_not_supported = allocations are not allowed in generic constants
-ty_utils_field_not_supported = field access is not supported in generic constants
+ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
ty_utils_const_block_not_supported = const blocks are not supported in generic constants
-ty_utils_adt_not_supported = struct/enum construction is not supported in generic constants
+ty_utils_control_flow_not_supported = control flow is not supported in generic constants
-ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants
+ty_utils_field_not_supported = field access is not supported in generic constants
-ty_utils_yield_not_supported = generator control flow is not allowed in generic constants
+ty_utils_generic_constant_too_complex = overly complex generic constant
+ .help = consider moving this anonymous constant into a `const` function
+ .maybe_supported = this operation may be supported in the future
-ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants
+ty_utils_impl_trait_duplicate_arg = non-defining opaque type use in defining scope
+ .label = generic argument `{$arg}` used twice
+ .note = for this opaque type
-ty_utils_box_not_supported = allocations are not allowed in generic constants
+ty_utils_impl_trait_not_param = non-defining opaque type use in defining scope
+ .label = argument `{$arg}` is not a generic parameter
+ .note = for this opaque type
-ty_utils_binary_not_supported = unsupported binary operation in generic constants
+ty_utils_index_not_supported = indexing is not supported in generic constants
+
+ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
ty_utils_logical_op_not_supported = unsupported operation in generic constants, short-circuiting operations would imply control flow
-ty_utils_assign_not_supported = assignment is not supported in generic constants
+ty_utils_loop_not_supported = loops and loop control flow are not supported in generic constants
-ty_utils_closure_and_return_not_supported = closures and function keywords are not supported in generic constants
+ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field
-ty_utils_control_flow_not_supported = control flow is not supported in generic constants
+ty_utils_needs_drop_overflow = overflow while checking whether `{$query_ty}` requires drop
-ty_utils_inline_asm_not_supported = assembly is not supported in generic constants
+ty_utils_never_to_any_not_supported = coercing the `never` type is not supported in generic constants
+
+ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
ty_utils_operation_not_supported = unsupported operation in generic constants
-ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item
+ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
-ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length
+ty_utils_pointer_not_supported = pointer casts are not allowed in generic constants
-ty_utils_multiple_array_fields_simd_type = monomorphising SIMD type `{$ty}` with more than one array field
+ty_utils_tuple_not_supported = tuple construction is not supported in generic constants
-ty_utils_oversized_simd_type = monomorphising SIMD type `{$ty}` of length greater than {$max_lanes}
+ty_utils_unexpected_fnptr_associated_item = `FnPtr` trait with unexpected associated item
-ty_utils_non_primitive_simd_type = monomorphising SIMD type `{$ty}` with a non-primitive-scalar (integer/float/pointer) element type `{$e_ty}`
+ty_utils_yield_not_supported = generator control flow is not allowed in generic constants
+
+ty_utils_zero_length_simd_type = monomorphising SIMD type `{$ty}` of zero length
diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs
index 271284b2d..15c191046 100644
--- a/compiler/rustc_ty_utils/src/abi.rs
+++ b/compiler/rustc_ty_utils/src/abi.rs
@@ -1,5 +1,6 @@
use rustc_hir as hir;
use rustc_hir::lang_items::LangItem;
+use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{
fn_can_unwind, FnAbiError, HasParamEnv, HasTyCtxt, LayoutCx, LayoutOf, TyAndLayout,
};
@@ -14,8 +15,8 @@ use rustc_target::spec::abi::Abi as SpecAbi;
use std::iter;
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { fn_abi_of_fn_ptr, fn_abi_of_instance, ..*providers };
}
// NOTE(eddyb) this is private to avoid using it from outside of
@@ -237,6 +238,7 @@ fn adjust_for_rust_scalar<'tcx>(
layout: TyAndLayout<'tcx>,
offset: Size,
is_return: bool,
+ drop_target_pointee: Option<Ty<'tcx>>,
) {
// Booleans are always a noundef i1 that needs to be zero-extended.
if scalar.is_bool() {
@@ -250,14 +252,24 @@ fn adjust_for_rust_scalar<'tcx>(
}
// Only pointer types handled below.
- let Scalar::Initialized { value: Pointer(_), valid_range} = scalar else { return };
+ let Scalar::Initialized { value: Pointer(_), valid_range } = scalar else { return };
- if !valid_range.contains(0) {
+ // Set `nonnull` if the validity range excludes zero, or for the argument to `drop_in_place`,
+ // which must be nonnull per its documented safety requirements.
+ if !valid_range.contains(0) || drop_target_pointee.is_some() {
attrs.set(ArgAttribute::NonNull);
}
if let Some(pointee) = layout.pointee_info_at(&cx, offset) {
- if let Some(kind) = pointee.safe {
+ let kind = if let Some(kind) = pointee.safe {
+ Some(kind)
+ } else if let Some(pointee) = drop_target_pointee {
+ // The argument to `drop_in_place` is semantically equivalent to a mutable reference.
+ Some(PointerKind::MutableRef { unpin: pointee.is_unpin(cx.tcx, cx.param_env()) })
+ } else {
+ None
+ };
+ if let Some(kind) = kind {
attrs.pointee_align = Some(pointee.align);
// `Box` are not necessarily dereferenceable for the entire duration of the function as
@@ -361,10 +373,18 @@ fn fn_abi_new_uncached<'tcx>(
use SpecAbi::*;
let rust_abi = matches!(sig.abi, RustIntrinsic | PlatformIntrinsic | Rust | RustCall);
+ let is_drop_in_place =
+ fn_def_id.is_some() && fn_def_id == cx.tcx.lang_items().drop_in_place_fn();
+
let arg_of = |ty: Ty<'tcx>, arg_idx: Option<usize>| -> Result<_, FnAbiError<'tcx>> {
let span = tracing::debug_span!("arg_of");
let _entered = span.enter();
let is_return = arg_idx.is_none();
+ let is_drop_target = is_drop_in_place && arg_idx == Some(0);
+ let drop_target_pointee = is_drop_target.then(|| match ty.kind() {
+ ty::RawPtr(ty::TypeAndMut { ty, .. }) => *ty,
+ _ => bug!("argument to drop_in_place is not a raw ptr: {:?}", ty),
+ });
let layout = cx.layout_of(ty)?;
let layout = if force_thin_self_ptr && arg_idx == Some(0) {
@@ -378,7 +398,15 @@ fn fn_abi_new_uncached<'tcx>(
let mut arg = ArgAbi::new(cx, layout, |layout, scalar, offset| {
let mut attrs = ArgAttributes::new();
- adjust_for_rust_scalar(*cx, &mut attrs, scalar, *layout, offset, is_return);
+ adjust_for_rust_scalar(
+ *cx,
+ &mut attrs,
+ scalar,
+ *layout,
+ offset,
+ is_return,
+ drop_target_pointee,
+ );
attrs
});
diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs
index de1e1a527..ed574f22e 100644
--- a/compiler/rustc_ty_utils/src/assoc.rs
+++ b/compiler/rustc_ty_utils/src/assoc.rs
@@ -4,11 +4,12 @@ use rustc_hir::def::DefKind;
use rustc_hir::def_id::{DefId, DefIdMap, LocalDefId};
use rustc_hir::definitions::DefPathData;
use rustc_hir::intravisit::{self, Visitor};
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, ImplTraitInTraitData, InternalSubsts, TyCtxt};
use rustc_span::symbol::kw;
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
associated_item,
associated_item_def_ids,
associated_items,
@@ -334,7 +335,7 @@ fn associated_type_for_impl_trait_in_trait(
parent_count,
params,
param_def_id_to_index,
- has_self: false,
+ has_self: opaque_ty_generics.has_self,
has_late_bound_regions: opaque_ty_generics.has_late_bound_regions,
}
});
diff --git a/compiler/rustc_ty_utils/src/common_traits.rs b/compiler/rustc_ty_utils/src/common_traits.rs
index 3b1abdcb2..51b908881 100644
--- a/compiler/rustc_ty_utils/src/common_traits.rs
+++ b/compiler/rustc_ty_utils/src/common_traits.rs
@@ -2,6 +2,7 @@
use rustc_hir::lang_items::LangItem;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_trait_selection::traits;
@@ -32,12 +33,6 @@ fn is_item_raw<'tcx>(
traits::type_known_to_meet_bound_modulo_regions(&infcx, param_env, ty, trait_def_id)
}
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
- is_copy_raw,
- is_sized_raw,
- is_freeze_raw,
- is_unpin_raw,
- ..*providers
- };
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers { is_copy_raw, is_sized_raw, is_freeze_raw, is_unpin_raw, ..*providers };
}
diff --git a/compiler/rustc_ty_utils/src/consts.rs b/compiler/rustc_ty_utils/src/consts.rs
index b67607a4d..1219bb400 100644
--- a/compiler/rustc_ty_utils/src/consts.rs
+++ b/compiler/rustc_ty_utils/src/consts.rs
@@ -2,6 +2,7 @@ use rustc_errors::ErrorGuaranteed;
use rustc_hir::def::DefKind;
use rustc_hir::def_id::LocalDefId;
use rustc_middle::mir::interpret::{LitToConstError, LitToConstInput};
+use rustc_middle::query::Providers;
use rustc_middle::thir::visit;
use rustc_middle::thir::visit::Visitor;
use rustc_middle::ty::abstract_const::CastKind;
@@ -115,9 +116,7 @@ fn recurse_build<'tcx>(
let sp = node.span;
match tcx.at(sp).lit_to_const(LitToConstInput { lit: &lit.node, ty: node.ty, neg }) {
Ok(c) => c,
- Err(LitToConstError::Reported(guar)) => {
- tcx.const_error_with_guaranteed(node.ty, guar)
- }
+ Err(LitToConstError::Reported(guar)) => tcx.const_error(node.ty, guar),
Err(LitToConstError::TypeError) => {
bug!("encountered type error in lit_to_const")
}
@@ -132,7 +131,7 @@ fn recurse_build<'tcx>(
tcx.mk_const(val, node.ty)
}
&ExprKind::NamedConst { def_id, substs, user_ty: _ } => {
- let uneval = ty::UnevaluatedConst::new(ty::WithOptConstParam::unknown(def_id), substs);
+ let uneval = ty::UnevaluatedConst::new(def_id, substs);
tcx.mk_const(uneval, node.ty)
}
ExprKind::ConstParam { param, .. } => tcx.mk_const(*param, node.ty),
@@ -256,6 +255,7 @@ fn recurse_build<'tcx>(
ExprKind::VarRef { .. }
| ExprKind::UpvarRef { .. }
| ExprKind::StaticRef { .. }
+ | ExprKind::OffsetOf { .. }
| ExprKind::ThreadLocalRef(_) => {
error(GenericConstantTooComplexSub::OperationNotSupported(node.span))?
}
@@ -347,6 +347,7 @@ impl<'a, 'tcx> IsThirPolymorphic<'a, 'tcx> {
| thir::ExprKind::ZstLiteral { .. }
| thir::ExprKind::StaticRef { .. }
| thir::ExprKind::InlineAsm(_)
+ | thir::ExprKind::OffsetOf { .. }
| thir::ExprKind::ThreadLocalRef(_)
| thir::ExprKind::Yield { .. } => false,
}
@@ -391,52 +392,36 @@ impl<'a, 'tcx> visit::Visitor<'a, 'tcx> for IsThirPolymorphic<'a, 'tcx> {
/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead.
pub fn thir_abstract_const(
tcx: TyCtxt<'_>,
- def: ty::WithOptConstParam<LocalDefId>,
-) -> Result<Option<ty::Const<'_>>, ErrorGuaranteed> {
- if tcx.features().generic_const_exprs {
- match tcx.def_kind(def.did) {
- // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
- // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
- // we want to look into them or treat them as opaque projections.
- //
- // Right now we do neither of that and simply always fail to unify them.
- DefKind::AnonConst | DefKind::InlineConst => (),
- _ => return Ok(None),
- }
-
- let body = tcx.thir_body(def)?;
- let (body, body_id) = (&*body.0.borrow(), body.1);
+ def: LocalDefId,
+) -> Result<Option<ty::EarlyBinder<ty::Const<'_>>>, ErrorGuaranteed> {
+ if !tcx.features().generic_const_exprs {
+ return Ok(None);
+ }
- let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
- visit::walk_expr(&mut is_poly_vis, &body[body_id]);
- if !is_poly_vis.is_poly {
- return Ok(None);
- }
+ match tcx.def_kind(def) {
+ // FIXME(generic_const_exprs): We currently only do this for anonymous constants,
+ // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether
+ // we want to look into them or treat them as opaque projections.
+ //
+ // Right now we do neither of that and simply always fail to unify them.
+ DefKind::AnonConst | DefKind::InlineConst => (),
+ _ => return Ok(None),
+ }
- let root_span = body.exprs[body_id].span;
+ let body = tcx.thir_body(def)?;
+ let (body, body_id) = (&*body.0.borrow(), body.1);
- Some(recurse_build(tcx, body, body_id, root_span)).transpose()
- } else {
- Ok(None)
+ let mut is_poly_vis = IsThirPolymorphic { is_poly: false, thir: body };
+ visit::walk_expr(&mut is_poly_vis, &body[body_id]);
+ if !is_poly_vis.is_poly {
+ return Ok(None);
}
+
+ let root_span = body.exprs[body_id].span;
+
+ Ok(Some(ty::EarlyBinder(recurse_build(tcx, body, body_id, root_span)?)))
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
- destructure_const,
- thir_abstract_const: |tcx, def_id| {
- if let Some(def) = ty::WithOptConstParam::try_lookup(def_id, tcx) {
- tcx.thir_abstract_const_of_const_arg(def)
- } else {
- thir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id))
- }
- },
- thir_abstract_const_of_const_arg: |tcx, (did, param_did)| {
- thir_abstract_const(
- tcx,
- ty::WithOptConstParam { did, const_param_did: Some(param_did) },
- )
- },
- ..*providers
- };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { destructure_const, thir_abstract_const, ..*providers };
}
diff --git a/compiler/rustc_ty_utils/src/errors.rs b/compiler/rustc_ty_utils/src/errors.rs
index 3d3fc50e6..553bf40ef 100644
--- a/compiler/rustc_ty_utils/src/errors.rs
+++ b/compiler/rustc_ty_utils/src/errors.rs
@@ -1,7 +1,7 @@
//! Errors emitted by ty_utils
use rustc_macros::{Diagnostic, Subdiagnostic};
-use rustc_middle::ty::Ty;
+use rustc_middle::ty::{GenericArg, Ty};
use rustc_span::Span;
#[derive(Diagnostic)]
@@ -100,3 +100,25 @@ pub struct NonPrimitiveSimdType<'tcx> {
pub ty: Ty<'tcx>,
pub e_ty: Ty<'tcx>,
}
+
+#[derive(Diagnostic)]
+#[diag(ty_utils_impl_trait_duplicate_arg)]
+pub struct DuplicateArg<'tcx> {
+ pub arg: GenericArg<'tcx>,
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note]
+ pub opaque_span: Span,
+}
+
+#[derive(Diagnostic)]
+#[diag(ty_utils_impl_trait_not_param)]
+pub struct NotParam<'tcx> {
+ pub arg: GenericArg<'tcx>,
+ #[primary_span]
+ #[label]
+ pub span: Span,
+ #[note]
+ pub opaque_span: Span,
+}
diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs
index 56d6cc28b..081be0658 100644
--- a/compiler/rustc_ty_utils/src/implied_bounds.rs
+++ b/compiler/rustc_ty_utils/src/implied_bounds.rs
@@ -1,8 +1,9 @@
use rustc_hir::{def::DefKind, def_id::DefId};
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { assumed_wf_types, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { assumed_wf_types, ..*providers };
}
fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
@@ -31,6 +32,18 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
}
}
DefKind::AssocConst | DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+ DefKind::OpaqueTy => match tcx.def_kind(tcx.parent(def_id)) {
+ DefKind::TyAlias => ty::List::empty(),
+ DefKind::AssocTy => tcx.assumed_wf_types(tcx.parent(def_id)),
+ // Nested opaque types only occur in associated types:
+ // ` type Opaque<T> = impl Trait<&'static T, AssocTy = impl Nested>; `
+ // assumed_wf_types should include those of `Opaque<T>`, `Opaque<T>` itself
+ // and `&'static T`.
+ DefKind::OpaqueTy => bug!("unimplemented implied bounds for neseted opaque types"),
+ def_kind @ _ => {
+ bug!("unimplemented implied bounds for opaque types with parent {def_kind:?}")
+ }
+ },
DefKind::Mod
| DefKind::Struct
| DefKind::Union
@@ -51,7 +64,6 @@ fn assumed_wf_types(tcx: TyCtxt<'_>, def_id: DefId) -> &ty::List<Ty<'_>> {
| DefKind::ForeignMod
| DefKind::AnonConst
| DefKind::InlineConst
- | DefKind::OpaqueTy
| DefKind::ImplTraitPlaceholder
| DefKind::Field
| DefKind::LifetimeParam
diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs
index 0a6c11809..36a20c78f 100644
--- a/compiler/rustc_ty_utils/src/instance.rs
+++ b/compiler/rustc_ty_utils/src/instance.rs
@@ -1,6 +1,7 @@
use rustc_errors::ErrorGuaranteed;
-use rustc_hir::def_id::{DefId, LocalDefId};
+use rustc_hir::def_id::DefId;
use rustc_infer::infer::TyCtxtInferExt;
+use rustc_middle::query::Providers;
use rustc_middle::traits::CodegenObligationError;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::{self, Instance, TyCtxt, TypeVisitableExt};
@@ -14,54 +15,25 @@ fn resolve_instance<'tcx>(
tcx: TyCtxt<'tcx>,
key: ty::ParamEnvAnd<'tcx, (DefId, SubstsRef<'tcx>)>,
) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
- let (param_env, (did, substs)) = key.into_parts();
- if let Some(did) = did.as_local() {
- if let Some(param_did) = tcx.opt_const_param_of(did) {
- return tcx.resolve_instance_of_const_arg(param_env.and((did, param_did, substs)));
- }
- }
-
- inner_resolve_instance(tcx, param_env.and((ty::WithOptConstParam::unknown(did), substs)))
-}
-
-fn resolve_instance_of_const_arg<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, (LocalDefId, DefId, SubstsRef<'tcx>)>,
-) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
- let (param_env, (did, const_param_did, substs)) = key.into_parts();
- inner_resolve_instance(
- tcx,
- param_env.and((
- ty::WithOptConstParam { did: did.to_def_id(), const_param_did: Some(const_param_did) },
- substs,
- )),
- )
-}
-
-fn inner_resolve_instance<'tcx>(
- tcx: TyCtxt<'tcx>,
- key: ty::ParamEnvAnd<'tcx, (ty::WithOptConstParam<DefId>, SubstsRef<'tcx>)>,
-) -> Result<Option<Instance<'tcx>>, ErrorGuaranteed> {
let (param_env, (def, substs)) = key.into_parts();
- let result = if let Some(trait_def_id) = tcx.trait_of_item(def.did) {
+ let result = if let Some(trait_def_id) = tcx.trait_of_item(def) {
debug!(" => associated item, attempting to find impl in param_env {:#?}", param_env);
resolve_associated_item(
tcx,
- def.did,
+ def,
param_env,
trait_def_id,
tcx.normalize_erasing_regions(param_env, substs),
)
} else {
- let ty = tcx.type_of(def.def_id_for_type_of());
- let item_type =
- tcx.subst_and_normalize_erasing_regions(substs, param_env, ty.skip_binder());
+ let ty = tcx.type_of(def);
+ let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, ty);
let def = match *item_type.kind() {
ty::FnDef(def_id, ..) if tcx.is_intrinsic(def_id) => {
debug!(" => intrinsic");
- ty::InstanceDef::Intrinsic(def.did)
+ ty::InstanceDef::Intrinsic(def)
}
ty::FnDef(def_id, substs) if Some(def_id) == tcx.lang_items().drop_in_place_fn() => {
let ty = substs.type_at(0);
@@ -113,7 +85,7 @@ fn resolve_associated_item<'tcx>(
Err(CodegenObligationError::Ambiguity) => {
let reported = tcx.sess.delay_span_bug(
tcx.def_span(trait_item_id),
- &format!(
+ format!(
"encountered ambiguity selecting `{trait_ref:?}` during codegen, presuming due to \
overflow or prior type error",
),
@@ -132,8 +104,8 @@ fn resolve_associated_item<'tcx>(
"resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}",
param_env, trait_item_id, rcvr_substs, impl_data
);
- assert!(!rcvr_substs.needs_infer());
- assert!(!trait_ref.needs_infer());
+ assert!(!rcvr_substs.has_infer());
+ assert!(!trait_ref.has_infer());
let trait_def_id = tcx.trait_id_of_impl(impl_data.impl_def_id).unwrap();
let trait_def = tcx.trait_def(trait_def_id);
@@ -205,19 +177,52 @@ fn resolve_associated_item<'tcx>(
Some(ty::Instance::new(leaf_def.item.def_id, substs))
}
- traits::ImplSource::Generator(generator_data) => Some(Instance {
- def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
- generator_data.generator_def_id,
- )),
- substs: generator_data.substs,
- }),
- traits::ImplSource::Future(future_data) => Some(Instance {
- def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown(
- future_data.generator_def_id,
- )),
- substs: future_data.substs,
- }),
+ traits::ImplSource::Generator(generator_data) => {
+ if cfg!(debug_assertions) && tcx.item_name(trait_item_id) != sym::resume {
+ // For compiler developers who'd like to add new items to `Generator`,
+ // you either need to generate a shim body, or perhaps return
+ // `InstanceDef::Item` pointing to a trait default method body if
+ // it is given a default implementation by the trait.
+ span_bug!(
+ tcx.def_span(generator_data.generator_def_id),
+ "no definition for `{trait_ref}::{}` for built-in generator type",
+ tcx.item_name(trait_item_id)
+ )
+ }
+ Some(Instance {
+ def: ty::InstanceDef::Item(generator_data.generator_def_id),
+ substs: generator_data.substs,
+ })
+ }
+ traits::ImplSource::Future(future_data) => {
+ if Some(trait_item_id) == tcx.lang_items().future_poll_fn() {
+ // `Future::poll` is generated by the compiler.
+ Some(Instance {
+ def: ty::InstanceDef::Item(future_data.generator_def_id),
+ substs: future_data.substs,
+ })
+ } else {
+ // All other methods are default methods of the `Future` trait.
+ // (this assumes that `ImplSource::Future` is only used for methods on `Future`)
+ debug_assert!(tcx.impl_defaultness(trait_item_id).has_value());
+ Some(Instance::new(trait_item_id, rcvr_substs))
+ }
+ }
traits::ImplSource::Closure(closure_data) => {
+ if cfg!(debug_assertions)
+ && ![sym::call, sym::call_mut, sym::call_once]
+ .contains(&tcx.item_name(trait_item_id))
+ {
+ // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+ // you either need to generate a shim body, or perhaps return
+ // `InstanceDef::Item` pointing to a trait default method body if
+ // it is given a default implementation by the trait.
+ span_bug!(
+ tcx.def_span(closure_data.closure_def_id),
+ "no definition for `{trait_ref}::{}` for built-in closure type",
+ tcx.item_name(trait_item_id)
+ )
+ }
let trait_closure_kind = tcx.fn_trait_kind_from_def_id(trait_id).unwrap();
Instance::resolve_closure(
tcx,
@@ -227,22 +232,37 @@ fn resolve_associated_item<'tcx>(
)
}
traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() {
- ty::FnDef(..) | ty::FnPtr(..) => Some(Instance {
- def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
- substs: rcvr_substs,
- }),
- _ => None,
- },
- traits::ImplSource::Object(ref data) => {
- if let Some(index) = traits::get_vtable_index_of_object_method(tcx, data, trait_item_id)
- {
+ ty::FnDef(..) | ty::FnPtr(..) => {
+ if cfg!(debug_assertions)
+ && ![sym::call, sym::call_mut, sym::call_once]
+ .contains(&tcx.item_name(trait_item_id))
+ {
+ // For compiler developers who'd like to add new items to `Fn`/`FnMut`/`FnOnce`,
+ // you either need to generate a shim body, or perhaps return
+ // `InstanceDef::Item` pointing to a trait default method body if
+ // it is given a default implementation by the trait.
+ bug!(
+ "no definition for `{trait_ref}::{}` for built-in fn type",
+ tcx.item_name(trait_item_id)
+ )
+ }
Some(Instance {
- def: ty::InstanceDef::Virtual(trait_item_id, index),
+ def: ty::InstanceDef::FnPtrShim(trait_item_id, data.fn_ty),
substs: rcvr_substs,
})
- } else {
- None
}
+ _ => bug!(
+ "no built-in definition for `{trait_ref}::{}` for non-fn type",
+ tcx.item_name(trait_item_id)
+ ),
+ },
+ traits::ImplSource::Object(ref data) => {
+ traits::get_vtable_index_of_object_method(tcx, data, trait_item_id).map(|index| {
+ Instance {
+ def: ty::InstanceDef::Virtual(trait_item_id, index),
+ substs: rcvr_substs,
+ }
+ })
}
traits::ImplSource::Builtin(..) => {
let lang_items = tcx.lang_items();
@@ -300,7 +320,6 @@ fn resolve_associated_item<'tcx>(
})
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers =
- ty::query::Providers { resolve_instance, resolve_instance_of_const_arg, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { resolve_instance, ..*providers };
}
diff --git a/compiler/rustc_ty_utils/src/layout.rs b/compiler/rustc_ty_utils/src/layout.rs
index 63ef1c724..16cd8bc8e 100644
--- a/compiler/rustc_ty_utils/src/layout.rs
+++ b/compiler/rustc_ty_utils/src/layout.rs
@@ -1,8 +1,9 @@
use hir::def_id::DefId;
use rustc_hir as hir;
use rustc_index::bit_set::BitSet;
-use rustc_index::vec::{IndexSlice, IndexVec};
+use rustc_index::{IndexSlice, IndexVec};
use rustc_middle::mir::{GeneratorLayout, GeneratorSavedLocal};
+use rustc_middle::query::Providers;
use rustc_middle::ty::layout::{
IntegerExt, LayoutCx, LayoutError, LayoutOf, TyAndLayout, MAX_SIMD_LANES,
};
@@ -22,8 +23,8 @@ use crate::errors::{
};
use crate::layout_sanity_check::sanity_check_layout;
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers { layout_of, ..*providers };
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers { layout_of, ..*providers };
}
#[instrument(skip(tcx, query), level = "debug")]
diff --git a/compiler/rustc_ty_utils/src/layout_sanity_check.rs b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
index a5311dbd1..c4a4cda68 100644
--- a/compiler/rustc_ty_utils/src/layout_sanity_check.rs
+++ b/compiler/rustc_ty_utils/src/layout_sanity_check.rs
@@ -4,7 +4,7 @@ use rustc_middle::ty::{
};
use rustc_target::abi::*;
-use std::cmp;
+use std::assert_matches::assert_matches;
/// Enforce some basic invariants on layouts.
pub(super) fn sanity_check_layout<'tcx>(
@@ -68,21 +68,31 @@ pub(super) fn sanity_check_layout<'tcx>(
}
fn check_layout_abi<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, layout: &TyAndLayout<'tcx>) {
+ // Verify the ABI mandated alignment and size.
+ let align = layout.abi.inherent_align(cx).map(|align| align.abi);
+ let size = layout.abi.inherent_size(cx);
+ let Some((align, size)) = align.zip(size) else {
+ assert_matches!(
+ layout.layout.abi(),
+ Abi::Uninhabited | Abi::Aggregate { .. },
+ "ABI unexpectedly missing alignment and/or size in {layout:#?}"
+ );
+ return
+ };
+ assert_eq!(
+ layout.layout.align().abi,
+ align,
+ "alignment mismatch between ABI and layout in {layout:#?}"
+ );
+ assert_eq!(
+ layout.layout.size(),
+ size,
+ "size mismatch between ABI and layout in {layout:#?}"
+ );
+
+ // Verify per-ABI invariants
match layout.layout.abi() {
- Abi::Scalar(scalar) => {
- // No padding in scalars.
- let size = scalar.size(cx);
- let align = scalar.align(cx).abi;
- assert_eq!(
- layout.layout.size(),
- size,
- "size mismatch between ABI and layout in {layout:#?}"
- );
- assert_eq!(
- layout.layout.align().abi,
- align,
- "alignment mismatch between ABI and layout in {layout:#?}"
- );
+ Abi::Scalar(_) => {
// Check that this matches the underlying field.
let inner = skip_newtypes(cx, layout);
assert!(
@@ -135,24 +145,6 @@ pub(super) fn sanity_check_layout<'tcx>(
}
}
Abi::ScalarPair(scalar1, scalar2) => {
- // Sanity-check scalar pairs. Computing the expected size and alignment is a bit of work.
- let size1 = scalar1.size(cx);
- let align1 = scalar1.align(cx).abi;
- let size2 = scalar2.size(cx);
- let align2 = scalar2.align(cx).abi;
- let align = cmp::max(align1, align2);
- let field2_offset = size1.align_to(align2);
- let size = (field2_offset + size2).align_to(align);
- assert_eq!(
- layout.layout.size(),
- size,
- "size mismatch between ABI and layout in {layout:#?}"
- );
- assert_eq!(
- layout.layout.align().abi,
- align,
- "alignment mismatch between ABI and layout in {layout:#?}",
- );
// Check that the underlying pair of fields matches.
let inner = skip_newtypes(cx, layout);
assert!(
@@ -189,8 +181,9 @@ pub(super) fn sanity_check_layout<'tcx>(
"`ScalarPair` layout for type with less than two non-ZST fields: {inner:#?}"
)
});
- assert!(
- fields.next().is_none(),
+ assert_matches!(
+ fields.next(),
+ None,
"`ScalarPair` layout for type with at least three non-ZST fields: {inner:#?}"
);
// The fields might be in opposite order.
@@ -200,6 +193,10 @@ pub(super) fn sanity_check_layout<'tcx>(
(offset2, field2, offset1, field1)
};
// The fields should be at the right offset, and match the `scalar` layout.
+ let size1 = scalar1.size(cx);
+ let align1 = scalar1.align(cx).abi;
+ let size2 = scalar2.size(cx);
+ let align2 = scalar2.align(cx).abi;
assert_eq!(
offset1,
Size::ZERO,
@@ -213,10 +210,12 @@ pub(super) fn sanity_check_layout<'tcx>(
field1.align.abi, align1,
"`ScalarPair` first field with bad align in {inner:#?}",
);
- assert!(
- matches!(field1.abi, Abi::Scalar(_)),
+ assert_matches!(
+ field1.abi,
+ Abi::Scalar(_),
"`ScalarPair` first field with bad ABI in {inner:#?}",
);
+ let field2_offset = size1.align_to(align2);
assert_eq!(
offset2, field2_offset,
"`ScalarPair` second field at bad offset in {inner:#?}",
@@ -229,27 +228,14 @@ pub(super) fn sanity_check_layout<'tcx>(
field2.align.abi, align2,
"`ScalarPair` second field with bad align in {inner:#?}",
);
- assert!(
- matches!(field2.abi, Abi::Scalar(_)),
+ assert_matches!(
+ field2.abi,
+ Abi::Scalar(_),
"`ScalarPair` second field with bad ABI in {inner:#?}",
);
}
- Abi::Vector { count, element } => {
- // No padding in vectors, except possibly for trailing padding to make the size a multiple of align.
- let size = element.size(cx) * count;
- let align = cx.data_layout().vector_align(size).abi;
- let size = size.align_to(align); // needed e.g. for vectors of size 3
+ Abi::Vector { element, .. } => {
assert!(align >= element.align(cx).abi); // just sanity-checking `vector_align`.
- assert_eq!(
- layout.layout.size(),
- size,
- "size mismatch between ABI and layout in {layout:#?}"
- );
- assert_eq!(
- layout.layout.align().abi,
- align,
- "alignment mismatch between ABI and layout in {layout:#?}"
- );
// FIXME: Do some kind of check of the inner type, like for Scalar and ScalarPair.
}
Abi::Uninhabited | Abi::Aggregate { .. } => {} // Nothing to check.
@@ -285,7 +271,7 @@ pub(super) fn sanity_check_layout<'tcx>(
{
// These are never actually accessed anyway, so we can skip the coherence check
// for them. They also fail that check, since they have
- // `Aggregate`/`Uninhbaited` ABI even when the main type is
+ // `Aggregate`/`Uninhabited` ABI even when the main type is
// `Scalar`/`ScalarPair`. (Note that sometimes, variants with fields have size
// 0, and sometimes, variants without fields have non-0 size.)
continue;
diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs
index 2613445f3..55b8857ed 100644
--- a/compiler/rustc_ty_utils/src/lib.rs
+++ b/compiler/rustc_ty_utils/src/lib.rs
@@ -5,6 +5,7 @@
//! This API is completely unstable and subject to change.
#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")]
+#![feature(assert_matches)]
#![feature(iterator_try_collect)]
#![feature(let_chains)]
#![feature(never_type)]
@@ -19,8 +20,8 @@ extern crate rustc_middle;
extern crate tracing;
use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage};
-use rustc_macros::fluent_messages;
-use rustc_middle::ty::query::Providers;
+use rustc_fluent_macro::fluent_messages;
+use rustc_middle::query::Providers;
mod abi;
mod assoc;
@@ -32,6 +33,7 @@ pub mod instance;
mod layout;
mod layout_sanity_check;
mod needs_drop;
+mod opaque_types;
pub mod representability;
mod structural_match;
mod ty;
@@ -46,6 +48,7 @@ pub fn provide(providers: &mut Providers) {
implied_bounds::provide(providers);
layout::provide(providers);
needs_drop::provide(providers);
+ opaque_types::provide(providers);
representability::provide(providers);
ty::provide(providers);
instance::provide(providers);
diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs
index de7fd0031..1f9701b93 100644
--- a/compiler/rustc_ty_utils/src/needs_drop.rs
+++ b/compiler/rustc_ty_utils/src/needs_drop.rs
@@ -2,6 +2,7 @@
use rustc_data_structures::fx::FxHashSet;
use rustc_hir::def_id::DefId;
+use rustc_middle::query::Providers;
use rustc_middle::ty::subst::SubstsRef;
use rustc_middle::ty::util::{needs_drop_components, AlwaysRequiresDrop};
use rustc_middle::ty::{self, EarlyBinder, Ty, TyCtxt};
@@ -132,7 +133,7 @@ where
_ => {
tcx.sess.delay_span_bug(
tcx.hir().span_if_local(def_id).unwrap_or(DUMMY_SP),
- &format!("unexpected generator witness type {:?}", witness),
+ format!("unexpected generator witness type {:?}", witness),
);
return Some(Err(AlwaysRequiresDrop));
}
@@ -243,7 +244,7 @@ fn drop_tys_helper<'tcx>(
} else {
let field_tys = adt_def.all_fields().map(|field| {
let r = tcx.type_of(field.did).subst(tcx, substs);
- debug!("drop_tys_helper: Subst into {:?} with {:?} gettng {:?}", field, substs, r);
+ debug!("drop_tys_helper: Subst into {:?} with {:?} getting {:?}", field, substs, r);
r
});
if only_significant {
@@ -323,8 +324,8 @@ fn adt_significant_drop_tys(
.map(|components| tcx.mk_type_list(&components))
}
-pub(crate) fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub(crate) fn provide(providers: &mut Providers) {
+ *providers = Providers {
needs_drop_raw,
has_significant_drop_raw,
adt_drop_tys,
diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs
new file mode 100644
index 000000000..4e91dd380
--- /dev/null
+++ b/compiler/rustc_ty_utils/src/opaque_types.rs
@@ -0,0 +1,198 @@
+use rustc_data_structures::fx::FxHashSet;
+use rustc_errors::ErrorGuaranteed;
+use rustc_hir::{def::DefKind, def_id::LocalDefId};
+use rustc_middle::query::Providers;
+use rustc_middle::ty::util::{CheckRegions, NotUniqueParam};
+use rustc_middle::ty::{self, Ty, TyCtxt};
+use rustc_middle::ty::{TypeSuperVisitable, TypeVisitable, TypeVisitor};
+use rustc_span::Span;
+use rustc_type_ir::AliasKind;
+use std::ops::ControlFlow;
+
+use crate::errors::{DuplicateArg, NotParam};
+
+struct OpaqueTypeCollector<'tcx> {
+ tcx: TyCtxt<'tcx>,
+ opaques: Vec<LocalDefId>,
+ /// The `DefId` of the item which we are collecting opaque types for.
+ item: LocalDefId,
+
+ /// Avoid infinite recursion due to recursive declarations.
+ seen: FxHashSet<LocalDefId>,
+}
+
+impl<'tcx> OpaqueTypeCollector<'tcx> {
+ fn collect(
+ tcx: TyCtxt<'tcx>,
+ item: LocalDefId,
+ val: ty::Binder<'tcx, impl TypeVisitable<TyCtxt<'tcx>>>,
+ ) -> Vec<LocalDefId> {
+ let mut collector = Self { tcx, opaques: Vec::new(), item, seen: Default::default() };
+ val.skip_binder().visit_with(&mut collector);
+ collector.opaques
+ }
+
+ fn span(&self) -> Span {
+ self.tcx.def_span(self.item)
+ }
+
+ fn parent(&self) -> Option<LocalDefId> {
+ match self.tcx.def_kind(self.item) {
+ DefKind::Fn => None,
+ DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
+ Some(self.tcx.local_parent(self.item))
+ }
+ other => span_bug!(
+ self.tcx.def_span(self.item),
+ "unhandled item with opaque types: {other:?}"
+ ),
+ }
+ }
+}
+
+impl<'tcx> TypeVisitor<TyCtxt<'tcx>> for OpaqueTypeCollector<'tcx> {
+ type BreakTy = ErrorGuaranteed;
+
+ #[instrument(skip(self), ret, level = "trace")]
+ fn visit_ty(&mut self, t: Ty<'tcx>) -> ControlFlow<ErrorGuaranteed> {
+ match t.kind() {
+ ty::Alias(AliasKind::Opaque, alias_ty) if alias_ty.def_id.is_local() => {
+ if !self.seen.insert(alias_ty.def_id.expect_local()) {
+ return ControlFlow::Continue(());
+ }
+ match self.tcx.uses_unique_generic_params(alias_ty.substs, CheckRegions::Bound) {
+ Ok(()) => {
+ // FIXME: implement higher kinded lifetime bounds on nested opaque types. They are not
+ // supported at all, so this is sound to do, but once we want to support them, you'll
+ // start seeing the error below.
+
+ self.opaques.push(alias_ty.def_id.expect_local());
+
+ // Collect opaque types nested within the associated type bounds of this opaque type.
+ for (pred, _span) in self
+ .tcx
+ .explicit_item_bounds(alias_ty.def_id)
+ .subst_iter_copied(self.tcx, alias_ty.substs)
+ {
+ trace!(?pred);
+ pred.visit_with(self)?;
+ }
+
+ ControlFlow::Continue(())
+ }
+ Err(NotUniqueParam::NotParam(arg)) => {
+ let err = self.tcx.sess.emit_err(NotParam {
+ arg,
+ span: self.span(),
+ opaque_span: self.tcx.def_span(alias_ty.def_id),
+ });
+ ControlFlow::Break(err)
+ }
+ Err(NotUniqueParam::DuplicateParam(arg)) => {
+ let err = self.tcx.sess.emit_err(DuplicateArg {
+ arg,
+ span: self.span(),
+ opaque_span: self.tcx.def_span(alias_ty.def_id),
+ });
+ ControlFlow::Break(err)
+ }
+ }
+ }
+ ty::Alias(AliasKind::Projection, alias_ty) => {
+ if let Some(parent) = self.parent() {
+ trace!(?alias_ty);
+ let (trait_ref, own_substs) = alias_ty.trait_ref_and_own_substs(self.tcx);
+
+ trace!(?trait_ref, ?own_substs);
+ // This avoids having to do normalization of `Self::AssocTy` by only
+ // supporting the case of a method defining opaque types from assoc types
+ // in the same impl block.
+ if trait_ref.self_ty() == self.tcx.type_of(parent).subst_identity() {
+ for assoc in self.tcx.associated_items(parent).in_definition_order() {
+ trace!(?assoc);
+ if assoc.trait_item_def_id == Some(alias_ty.def_id) {
+ // We reconstruct the generic args of the associated type within the impl
+ // from the impl's generics and the generic args passed to the type via the
+ // projection.
+ let substs = ty::InternalSubsts::identity_for_item(
+ self.tcx,
+ parent.to_def_id(),
+ );
+ trace!(?substs);
+ let substs: Vec<_> =
+ substs.iter().chain(own_substs.iter().copied()).collect();
+ trace!(?substs);
+ // Find opaque types in this associated type.
+ return self
+ .tcx
+ .type_of(assoc.def_id)
+ .subst(self.tcx, &substs)
+ .visit_with(self);
+ }
+ }
+ }
+ }
+ t.super_visit_with(self)
+ }
+ _ => t.super_visit_with(self),
+ }
+ }
+}
+
+fn opaque_types_defined_by<'tcx>(tcx: TyCtxt<'tcx>, item: LocalDefId) -> &'tcx [LocalDefId] {
+ let kind = tcx.def_kind(item);
+ trace!(?kind);
+ // FIXME(type_alias_impl_trait): This is definitely still wrong except for RPIT and impl trait in assoc types.
+ match kind {
+ // We're also doing this for `AssocTy` for the wf checks in `check_opaque_meets_bounds`
+ DefKind::Fn | DefKind::AssocFn | DefKind::AssocTy | DefKind::AssocConst => {
+ let defined_opaques = match kind {
+ DefKind::Fn => {
+ OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
+ }
+ DefKind::AssocFn => {
+ OpaqueTypeCollector::collect(tcx, item, tcx.fn_sig(item).subst_identity())
+ }
+ DefKind::AssocTy | DefKind::AssocConst => OpaqueTypeCollector::collect(
+ tcx,
+ item,
+ ty::Binder::dummy(tcx.type_of(item).subst_identity()),
+ ),
+ _ => unreachable!(),
+ };
+ tcx.arena.alloc_from_iter(defined_opaques)
+ }
+ DefKind::Mod
+ | DefKind::Struct
+ | DefKind::Union
+ | DefKind::Enum
+ | DefKind::Variant
+ | DefKind::Trait
+ | DefKind::TyAlias
+ | DefKind::ForeignTy
+ | DefKind::TraitAlias
+ | DefKind::TyParam
+ | DefKind::Const
+ | DefKind::ConstParam
+ | DefKind::Static(_)
+ | DefKind::Ctor(_, _)
+ | DefKind::Macro(_)
+ | DefKind::ExternCrate
+ | DefKind::Use
+ | DefKind::ForeignMod
+ | DefKind::AnonConst
+ | DefKind::InlineConst
+ | DefKind::OpaqueTy
+ | DefKind::ImplTraitPlaceholder
+ | DefKind::Field
+ | DefKind::LifetimeParam
+ | DefKind::GlobalAsm
+ | DefKind::Impl { .. }
+ | DefKind::Closure
+ | DefKind::Generator => &[],
+ }
+}
+
+pub(super) fn provide(providers: &mut Providers) {
+ *providers = Providers { opaque_types_defined_by, ..*providers };
+}
diff --git a/compiler/rustc_ty_utils/src/representability.rs b/compiler/rustc_ty_utils/src/representability.rs
index 26d6deab8..0b5e27c2c 100644
--- a/compiler/rustc_ty_utils/src/representability.rs
+++ b/compiler/rustc_ty_utils/src/representability.rs
@@ -2,7 +2,7 @@
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Representability, Ty, TyCtxt};
use rustc_span::def_id::LocalDefId;
diff --git a/compiler/rustc_ty_utils/src/structural_match.rs b/compiler/rustc_ty_utils/src/structural_match.rs
index a55bb7e7e..215acbe2c 100644
--- a/compiler/rustc_ty_utils/src/structural_match.rs
+++ b/compiler/rustc_ty_utils/src/structural_match.rs
@@ -1,5 +1,5 @@
use rustc_hir::lang_items::LangItem;
-use rustc_middle::ty::query::Providers;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{self, Ty, TyCtxt};
use rustc_infer::infer::TyCtxtInferExt;
@@ -13,7 +13,7 @@ use rustc_trait_selection::traits::{ObligationCause, ObligationCtxt};
/// Note that this does *not* recursively check if the substructure of `adt_ty`
/// implements the traits.
fn has_structural_eq_impls<'tcx>(tcx: TyCtxt<'tcx>, adt_ty: Ty<'tcx>) -> bool {
- let ref infcx = tcx.infer_ctxt().build();
+ let infcx = &tcx.infer_ctxt().build();
let cause = ObligationCause::dummy();
let ocx = ObligationCtxt::new(infcx);
diff --git a/compiler/rustc_ty_utils/src/ty.rs b/compiler/rustc_ty_utils/src/ty.rs
index cb06c7acf..65dc3c39c 100644
--- a/compiler/rustc_ty_utils/src/ty.rs
+++ b/compiler/rustc_ty_utils/src/ty.rs
@@ -2,6 +2,7 @@ use rustc_data_structures::fx::{FxHashSet, FxIndexSet};
use rustc_hir as hir;
use rustc_hir::def::DefKind;
use rustc_index::bit_set::BitSet;
+use rustc_middle::query::Providers;
use rustc_middle::ty::{
self, Binder, EarlyBinder, ImplTraitInTraitData, Predicate, PredicateKind, ToPredicate, Ty,
TyCtxt, TypeSuperVisitable, TypeVisitable, TypeVisitor,
@@ -62,9 +63,8 @@ fn sized_constraint_for_ty<'tcx>(
// it on the impl.
let Some(sized_trait) = tcx.lang_items().sized_trait() else { return vec![ty] };
- let sized_predicate = ty::Binder::dummy(tcx.mk_trait_ref(sized_trait, [ty]))
- .without_const()
- .to_predicate(tcx);
+ let sized_predicate =
+ ty::TraitRef::new(tcx, sized_trait, [ty]).without_const().to_predicate(tcx);
let predicates = tcx.predicates_of(adtdef.did()).predicates;
if predicates.iter().any(|(p, _)| *p == sized_predicate) { vec![] } else { vec![ty] }
}
@@ -567,8 +567,8 @@ fn unsizing_params_for_adt<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> BitSet<u32
unsizing_params
}
-pub fn provide(providers: &mut ty::query::Providers) {
- *providers = ty::query::Providers {
+pub fn provide(providers: &mut Providers) {
+ *providers = Providers {
asyncness,
adt_sized_constraint,
param_env,
diff --git a/compiler/rustc_type_ir/src/codec.rs b/compiler/rustc_type_ir/src/codec.rs
index ee249050c..3b6389346 100644
--- a/compiler/rustc_type_ir/src/codec.rs
+++ b/compiler/rustc_type_ir/src/codec.rs
@@ -27,10 +27,13 @@ pub trait TyEncoder: Encoder {
const CLEAR_CROSS_CRATE: bool;
fn position(&self) -> usize;
+
fn type_shorthands(&mut self) -> &mut FxHashMap<<Self::I as Interner>::Ty, usize>;
+
fn predicate_shorthands(
&mut self,
) -> &mut FxHashMap<<Self::I as Interner>::PredicateKind, usize>;
+
fn encode_alloc_id(&mut self, alloc_id: &<Self::I as Interner>::AllocId);
}
@@ -40,10 +43,6 @@ pub trait TyDecoder: Decoder {
fn interner(&self) -> Self::I;
- fn peek_byte(&self) -> u8;
-
- fn position(&self) -> usize;
-
fn cached_ty_for_shorthand<F>(
&mut self,
shorthand: usize,
diff --git a/compiler/rustc_type_ir/src/fold.rs b/compiler/rustc_type_ir/src/fold.rs
index 3a053d4c6..371c61191 100644
--- a/compiler/rustc_type_ir/src/fold.rs
+++ b/compiler/rustc_type_ir/src/fold.rs
@@ -16,8 +16,10 @@
//! - Types of interest, for which the methods delegate to the folder.
//! - All other types, including generic containers like `Vec` and `Option`.
//! It defines a "skeleton" of how they should be folded.
-//! - `TypeSuperFoldable`. This is implemented only for each type of interest,
-//! and defines the folding "skeleton" for these types.
+//! - `TypeSuperFoldable`. This is implemented only for recursive types of
+//! interest, and defines the folding "skeleton" for these types. (This
+//! excludes `Region` because it is non-recursive, i.e. it never contains
+//! other types of interest.)
//! - `TypeFolder`/`FallibleTypeFolder`. One of these is implemented for each
//! folder. This defines how types of interest are folded.
//!
@@ -72,9 +74,9 @@ pub trait TypeFoldable<I: Interner>: TypeVisitable<I> {
// This trait is implemented for types of interest.
pub trait TypeSuperFoldable<I: Interner>: TypeFoldable<I> {
- /// Provides a default fold for a type of interest. This should only be
- /// called within `TypeFolder` methods, when a non-custom traversal is
- /// desired for the value of the type of interest passed to that method.
+ /// Provides a default fold for a recursive type of interest. This should
+ /// only be called within `TypeFolder` methods, when a non-custom traversal
+ /// is desired for the value of the type of interest passed to that method.
/// For example, in `MyFolder::try_fold_ty(ty)`, it is valid to call
/// `ty.try_super_fold_with(self)`, but any other folding should be done
/// with `xyz.try_fold_with(self)`.
@@ -118,11 +120,11 @@ pub trait TypeFolder<I: Interner>: FallibleTypeFolder<I, Error = !> {
t.super_fold_with(self)
}
- fn fold_region(&mut self, r: I::Region) -> I::Region
- where
- I::Region: TypeSuperFoldable<I>,
- {
- r.super_fold_with(self)
+ // The default region folder is a no-op because `Region` is non-recursive
+ // and has no `super_visit_with` method to call. That also explains the
+ // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
+ fn fold_region(&mut self, r: I::Region) -> I::Region {
+ r
}
fn fold_const(&mut self, c: I::Const) -> I::Const
@@ -167,11 +169,11 @@ pub trait FallibleTypeFolder<I: Interner>: Sized {
t.try_super_fold_with(self)
}
- fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error>
- where
- I::Region: TypeSuperFoldable<I>,
- {
- r.try_super_fold_with(self)
+ // The default region folder is a no-op because `Region` is non-recursive
+ // and has no `super_visit_with` method to call. That also explains the
+ // lack of `I::Region: TypeSuperFoldable<I>` bound on this method.
+ fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, Self::Error> {
+ Ok(r)
}
fn try_fold_const(&mut self, c: I::Const) -> Result<I::Const, Self::Error>
@@ -216,10 +218,7 @@ where
Ok(self.fold_ty(t))
}
- fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !>
- where
- I::Region: TypeSuperFoldable<I>,
- {
+ fn try_fold_region(&mut self, r: I::Region) -> Result<I::Region, !> {
Ok(self.fold_region(r))
}
diff --git a/compiler/rustc_type_ir/src/lib.rs b/compiler/rustc_type_ir/src/lib.rs
index a3c98ae00..f6b44bdf2 100644
--- a/compiler/rustc_type_ir/src/lib.rs
+++ b/compiler/rustc_type_ir/src/lib.rs
@@ -179,7 +179,7 @@ bitflags! {
/// Does this have `ConstKind::Param`?
const HAS_CT_PARAM = 1 << 2;
- const NEEDS_SUBST = TypeFlags::HAS_TY_PARAM.bits
+ const HAS_PARAM = TypeFlags::HAS_TY_PARAM.bits
| TypeFlags::HAS_RE_PARAM.bits
| TypeFlags::HAS_CT_PARAM.bits;
@@ -192,7 +192,7 @@ bitflags! {
/// Does this have inference variables? Used to determine whether
/// inference is required.
- const NEEDS_INFER = TypeFlags::HAS_TY_INFER.bits
+ const HAS_INFER = TypeFlags::HAS_TY_INFER.bits
| TypeFlags::HAS_RE_INFER.bits
| TypeFlags::HAS_CT_INFER.bits;
@@ -229,29 +229,32 @@ bitflags! {
/// Does this have `Projection`?
const HAS_TY_PROJECTION = 1 << 10;
+ /// Does this have `Inherent`?
+ const HAS_TY_INHERENT = 1 << 11;
/// Does this have `Opaque`?
- const HAS_TY_OPAQUE = 1 << 11;
+ const HAS_TY_OPAQUE = 1 << 12;
/// Does this have `ConstKind::Unevaluated`?
- const HAS_CT_PROJECTION = 1 << 12;
+ const HAS_CT_PROJECTION = 1 << 13;
/// Could this type be normalized further?
const HAS_PROJECTION = TypeFlags::HAS_TY_PROJECTION.bits
| TypeFlags::HAS_TY_OPAQUE.bits
+ | TypeFlags::HAS_TY_INHERENT.bits
| TypeFlags::HAS_CT_PROJECTION.bits;
/// Is an error type/const reachable?
- const HAS_ERROR = 1 << 13;
+ const HAS_ERROR = 1 << 14;
/// Does this have any region that "appears free" in the type?
/// Basically anything but `ReLateBound` and `ReErased`.
- const HAS_FREE_REGIONS = 1 << 14;
+ const HAS_FREE_REGIONS = 1 << 15;
/// Does this have any `ReLateBound` regions?
- const HAS_RE_LATE_BOUND = 1 << 15;
+ const HAS_RE_LATE_BOUND = 1 << 16;
/// Does this have any `Bound` types?
- const HAS_TY_LATE_BOUND = 1 << 16;
+ const HAS_TY_LATE_BOUND = 1 << 17;
/// Does this have any `ConstKind::Bound` consts?
- const HAS_CT_LATE_BOUND = 1 << 17;
+ const HAS_CT_LATE_BOUND = 1 << 18;
/// Does this have any bound variables?
/// Used to check if a global bound is safe to evaluate.
const HAS_LATE_BOUND = TypeFlags::HAS_RE_LATE_BOUND.bits
@@ -259,20 +262,20 @@ bitflags! {
| TypeFlags::HAS_CT_LATE_BOUND.bits;
/// Does this have any `ReErased` regions?
- const HAS_RE_ERASED = 1 << 18;
+ const HAS_RE_ERASED = 1 << 19;
/// Does this value have parameters/placeholders/inference variables which could be
/// replaced later, in a way that would change the results of `impl` specialization?
- const STILL_FURTHER_SPECIALIZABLE = 1 << 19;
+ const STILL_FURTHER_SPECIALIZABLE = 1 << 20;
/// Does this value have `InferTy::FreshTy/FreshIntTy/FreshFloatTy`?
- const HAS_TY_FRESH = 1 << 20;
+ const HAS_TY_FRESH = 1 << 21;
/// Does this value have `InferConst::Fresh`?
- const HAS_CT_FRESH = 1 << 21;
+ const HAS_CT_FRESH = 1 << 22;
/// Does this have `Generator` or `GeneratorWitness`?
- const HAS_TY_GENERATOR = 1 << 22;
+ const HAS_TY_GENERATOR = 1 << 23;
}
}
@@ -537,7 +540,7 @@ pub struct FloatVarValue(pub FloatTy);
rustc_index::newtype_index! {
/// A **ty**pe **v**ariable **ID**.
- #[debug_format = "_#{}t"]
+ #[debug_format = "?{}t"]
pub struct TyVid {}
}
@@ -640,7 +643,7 @@ impl UnifyKey for FloatVid {
}
}
-#[derive(Copy, Clone, PartialEq, Decodable, Encodable, Hash, HashStable_Generic)]
+#[derive(Copy, Clone, PartialEq, Eq, Decodable, Encodable, Hash, HashStable_Generic)]
#[rustc_pass_by_value]
pub enum Variance {
Covariant, // T<A> <: T<B> iff A <: B -- e.g., function return type
@@ -739,13 +742,13 @@ impl fmt::Debug for FloatVarValue {
impl fmt::Debug for IntVid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}i", self.index)
+ write!(f, "?{}i", self.index)
}
}
impl fmt::Debug for FloatVid {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- write!(f, "_#{}f", self.index)
+ write!(f, "?{}f", self.index)
}
}
diff --git a/compiler/rustc_type_ir/src/macros.rs b/compiler/rustc_type_ir/src/macros.rs
index 6c1810397..8c3cb2283 100644
--- a/compiler/rustc_type_ir/src/macros.rs
+++ b/compiler/rustc_type_ir/src/macros.rs
@@ -33,144 +33,3 @@ macro_rules! TrivialTypeTraversalImpls {
)+
};
}
-
-macro_rules! EnumTypeTraversalImpl {
- (impl<$($p:tt),*> TypeFoldable<$tcx:tt> for $s:path {
- $($variants:tt)*
- } $(where $($wc:tt)*)*) => {
- impl<$($p),*> $crate::fold::TypeFoldable<$tcx> for $s
- $(where $($wc)*)*
- {
- fn try_fold_with<V: $crate::fold::FallibleTypeFolder<$tcx>>(
- self,
- folder: &mut V,
- ) -> ::std::result::Result<Self, V::Error> {
- EnumTypeTraversalImpl!(@FoldVariants(self, folder) input($($variants)*) output())
- }
- }
- };
-
- (impl<$($p:tt),*> TypeVisitable<$tcx:tt> for $s:path {
- $($variants:tt)*
- } $(where $($wc:tt)*)*) => {
- impl<$($p),*> $crate::visit::TypeVisitable<$tcx> for $s
- $(where $($wc)*)*
- {
- fn visit_with<V: $crate::visit::TypeVisitor<$tcx>>(
- &self,
- visitor: &mut V,
- ) -> ::std::ops::ControlFlow<V::BreakTy> {
- EnumTypeTraversalImpl!(@VisitVariants(self, visitor) input($($variants)*) output())
- }
- }
- };
-
- (@FoldVariants($this:expr, $folder:expr) input() output($($output:tt)*)) => {
- Ok(match $this {
- $($output)*
- })
- };
-
- (@FoldVariants($this:expr, $folder:expr)
- input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @FoldVariants($this, $folder)
- input($($input)*)
- output(
- $variant ( $($variant_arg),* ) => {
- $variant (
- $($crate::fold::TypeFoldable::try_fold_with($variant_arg, $folder)?),*
- )
- }
- $($output)*
- )
- )
- };
-
- (@FoldVariants($this:expr, $folder:expr)
- input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @FoldVariants($this, $folder)
- input($($input)*)
- output(
- $variant { $($variant_arg),* } => {
- $variant {
- $($variant_arg: $crate::fold::TypeFoldable::fold_with(
- $variant_arg, $folder
- )?),* }
- }
- $($output)*
- )
- )
- };
-
- (@FoldVariants($this:expr, $folder:expr)
- input( ($variant:path), $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @FoldVariants($this, $folder)
- input($($input)*)
- output(
- $variant => { $variant }
- $($output)*
- )
- )
- };
-
- (@VisitVariants($this:expr, $visitor:expr) input() output($($output:tt)*)) => {
- match $this {
- $($output)*
- }
- };
-
- (@VisitVariants($this:expr, $visitor:expr)
- input( ($variant:path) ( $($variant_arg:ident),* ) , $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @VisitVariants($this, $visitor)
- input($($input)*)
- output(
- $variant ( $($variant_arg),* ) => {
- $($crate::visit::TypeVisitable::visit_with(
- $variant_arg, $visitor
- )?;)*
- ::std::ops::ControlFlow::Continue(())
- }
- $($output)*
- )
- )
- };
-
- (@VisitVariants($this:expr, $visitor:expr)
- input( ($variant:path) { $($variant_arg:ident),* $(,)? } , $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @VisitVariants($this, $visitor)
- input($($input)*)
- output(
- $variant { $($variant_arg),* } => {
- $($crate::visit::TypeVisitable::visit_with(
- $variant_arg, $visitor
- )?;)*
- ::std::ops::ControlFlow::Continue(())
- }
- $($output)*
- )
- )
- };
-
- (@VisitVariants($this:expr, $visitor:expr)
- input( ($variant:path), $($input:tt)*)
- output( $($output:tt)*) ) => {
- EnumTypeTraversalImpl!(
- @VisitVariants($this, $visitor)
- input($($input)*)
- output(
- $variant => { ::std::ops::ControlFlow::Continue(()) }
- $($output)*
- )
- )
- };
-}
diff --git a/compiler/rustc_type_ir/src/structural_impls.rs b/compiler/rustc_type_ir/src/structural_impls.rs
index 3ebe24104..45a2e9023 100644
--- a/compiler/rustc_type_ir/src/structural_impls.rs
+++ b/compiler/rustc_type_ir/src/structural_impls.rs
@@ -6,11 +6,10 @@ use crate::fold::{FallibleTypeFolder, TypeFoldable};
use crate::visit::{TypeVisitable, TypeVisitor};
use crate::Interner;
use rustc_data_structures::functor::IdFunctor;
-use rustc_index::vec::{Idx, IndexVec};
+use rustc_data_structures::sync::Lrc;
+use rustc_index::{Idx, IndexVec};
use std::ops::ControlFlow;
-use std::rc::Rc;
-use std::sync::Arc;
///////////////////////////////////////////////////////////////////////////
// Atomic structs
@@ -22,6 +21,7 @@ TrivialTypeTraversalImpls! {
(),
bool,
usize,
+ u8,
u16,
u32,
u64,
@@ -70,51 +70,49 @@ impl<I: Interner, A: TypeVisitable<I>, B: TypeVisitable<I>, C: TypeVisitable<I>>
}
}
-EnumTypeTraversalImpl! {
- impl<I, T> TypeFoldable<I> for Option<T> {
- (Some)(a),
- (None),
- } where I: Interner, T: TypeFoldable<I>
-}
-EnumTypeTraversalImpl! {
- impl<I, T> TypeVisitable<I> for Option<T> {
- (Some)(a),
- (None),
- } where I: Interner, T: TypeVisitable<I>
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Option<T> {
+ fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
+ Ok(match self {
+ Some(v) => Some(v.try_fold_with(folder)?),
+ None => None,
+ })
+ }
}
-EnumTypeTraversalImpl! {
- impl<I, T, E> TypeFoldable<I> for Result<T, E> {
- (Ok)(a),
- (Err)(a),
- } where I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>,
-}
-EnumTypeTraversalImpl! {
- impl<I, T, E> TypeVisitable<I> for Result<T, E> {
- (Ok)(a),
- (Err)(a),
- } where I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>,
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Option<T> {
+ fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
+ match self {
+ Some(v) => v.visit_with(visitor),
+ None => ControlFlow::Continue(()),
+ }
+ }
}
-impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Rc<T> {
+impl<I: Interner, T: TypeFoldable<I>, E: TypeFoldable<I>> TypeFoldable<I> for Result<T, E> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
- self.try_map_id(|value| value.try_fold_with(folder))
+ Ok(match self {
+ Ok(v) => Ok(v.try_fold_with(folder)?),
+ Err(e) => Err(e.try_fold_with(folder)?),
+ })
}
}
-impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Rc<T> {
+impl<I: Interner, T: TypeVisitable<I>, E: TypeVisitable<I>> TypeVisitable<I> for Result<T, E> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- (**self).visit_with(visitor)
+ match self {
+ Ok(v) => v.visit_with(visitor),
+ Err(e) => e.visit_with(visitor),
+ }
}
}
-impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Arc<T> {
+impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Lrc<T> {
fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
self.try_map_id(|value| value.try_fold_with(folder))
}
}
-impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Arc<T> {
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Lrc<T> {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
(**self).visit_with(visitor)
}
@@ -144,19 +142,11 @@ impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Vec<T> {
}
}
-impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
- fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
- self.iter().try_for_each(|t| t.visit_with(visitor))
- }
-}
+// `TypeFoldable` isn't impl'd for `&[T]`. It doesn't make sense in the general
+// case, because we can't return a new slice. But note that there are a couple
+// of trivial impls of `TypeFoldable` for specific slice types elsewhere.
-impl<I: Interner, T: TypeFoldable<I>> TypeFoldable<I> for Box<[T]> {
- fn try_fold_with<F: FallibleTypeFolder<I>>(self, folder: &mut F) -> Result<Self, F::Error> {
- self.try_map_id(|t| t.try_fold_with(folder))
- }
-}
-
-impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for Box<[T]> {
+impl<I: Interner, T: TypeVisitable<I>> TypeVisitable<I> for &[T] {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy> {
self.iter().try_for_each(|t| t.visit_with(visitor))
}
diff --git a/compiler/rustc_type_ir/src/sty.rs b/compiler/rustc_type_ir/src/sty.rs
index 62e699eef..f7344bacc 100644
--- a/compiler/rustc_type_ir/src/sty.rs
+++ b/compiler/rustc_type_ir/src/sty.rs
@@ -37,6 +37,7 @@ pub enum DynKind {
#[derive(Encodable, Decodable, HashStable_Generic)]
pub enum AliasKind {
Projection,
+ Inherent,
Opaque,
}
@@ -203,6 +204,10 @@ pub enum TyKind<I: Interner> {
/// `for<'a, T> &'a (): Trait<T>` and then convert the introduced bound variables
/// back to inference variables in a new inference context when inside of the query.
///
+ /// It is conventional to render anonymous bound types like `^N` or `^D_N`,
+ /// where `N` is the bound variable's anonymous index into the binder, and
+ /// `D` is the debruijn index, or totally omitted if the debruijn index is zero.
+ ///
/// See the `rustc-dev-guide` for more details about
/// [higher-ranked trait bounds][1] and [canonical queries][2].
///
@@ -212,6 +217,12 @@ pub enum TyKind<I: Interner> {
/// A placeholder type, used during higher ranked subtyping to instantiate
/// bound variables.
+ ///
+ /// It is conventional to render anonymous placeholer types like `!N` or `!U_N`,
+ /// where `N` is the placeholder variable's anonymous index (which corresponds
+ /// to the bound variable's index from the binder from which it was instantiated),
+ /// and `U` is the universe index in which it is instantiated, or totally omitted
+ /// if the universe index is zero.
Placeholder(I::PlaceholderType),
/// A type variable used during type checking.
diff --git a/compiler/rustc_type_ir/src/visit.rs b/compiler/rustc_type_ir/src/visit.rs
index 62239fd20..878c7aec6 100644
--- a/compiler/rustc_type_ir/src/visit.rs
+++ b/compiler/rustc_type_ir/src/visit.rs
@@ -13,8 +13,11 @@
//! - Types of interest, for which the methods delegate to the visitor.
//! - All other types, including generic containers like `Vec` and `Option`.
//! It defines a "skeleton" of how they should be visited.
-//! - `TypeSuperVisitable`. This is implemented only for each type of interest,
-//! and defines the visiting "skeleton" for these types.
+//! - `TypeSuperVisitable`. This is implemented only for recursive types of
+//! interest, and defines the visiting "skeleton" for these types. (This
+//! excludes `Region` because it is non-recursive, i.e. it never contains
+//! other types of interest.)
+//!
//! - `TypeVisitor`. This is implemented for each visitor. This defines how
//! types of interest are visited.
//!
@@ -62,12 +65,13 @@ pub trait TypeVisitable<I: Interner>: fmt::Debug + Clone {
fn visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
}
+// This trait is implemented for types of interest.
pub trait TypeSuperVisitable<I: Interner>: TypeVisitable<I> {
- /// Provides a default visit for a type of interest. This should only be
- /// called within `TypeVisitor` methods, when a non-custom traversal is
- /// desired for the value of the type of interest passed to that method.
- /// For example, in `MyVisitor::visit_ty(ty)`, it is valid to call
- /// `ty.super_visit_with(self)`, but any other visiting should be done
+ /// Provides a default visit for a recursive type of interest. This should
+ /// only be called within `TypeVisitor` methods, when a non-custom
+ /// traversal is desired for the value of the type of interest passed to
+ /// that method. For example, in `MyVisitor::visit_ty(ty)`, it is valid to
+ /// call `ty.super_visit_with(self)`, but any other visiting should be done
/// with `xyz.visit_with(self)`.
fn super_visit_with<V: TypeVisitor<I>>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>;
}
@@ -92,11 +96,11 @@ pub trait TypeVisitor<I: Interner>: Sized {
t.super_visit_with(self)
}
- fn visit_region(&mut self, r: I::Region) -> ControlFlow<Self::BreakTy>
- where
- I::Region: TypeSuperVisitable<I>,
- {
- r.super_visit_with(self)
+ // The default region visitor is a no-op because `Region` is non-recursive
+ // and has no `super_visit_with` method to call. That also explains the
+ // lack of `I::Region: TypeSuperVisitable<I>` bound.
+ fn visit_region(&mut self, _r: I::Region) -> ControlFlow<Self::BreakTy> {
+ ControlFlow::Continue(())
}
fn visit_const(&mut self, c: I::Const) -> ControlFlow<Self::BreakTy>